// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they begin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
//
// - Sun Tsu,
// "The Art of War"
using System;
using System.Globalization;
using System.IO;
using TheArtOfDev.HtmlRenderer.Adapters;
using TheArtOfDev.HtmlRenderer.Core.Dom;
using TheArtOfDev.HtmlRenderer.Core.Entities;
using TheArtOfDev.HtmlRenderer.Core.Utils;
namespace TheArtOfDev.HtmlRenderer.Core.Handlers
{
///
/// Handle context menu.
///
internal sealed class ContextMenuHandler : IDisposable
{
#region Fields and Consts
///
/// select all text
///
private static readonly string _selectAll;
///
/// copy selected text
///
private static readonly string _copy;
///
/// copy the link source
///
private static readonly string _copyLink;
///
/// open link (as left mouse click)
///
private static readonly string _openLink;
///
/// copy the source of the image
///
private static readonly string _copyImageLink;
///
/// copy image to clipboard
///
private static readonly string _copyImage;
///
/// save image to disk
///
private static readonly string _saveImage;
///
/// open video in browser
///
private static readonly string _openVideo;
///
/// copy video url to browser
///
private static readonly string _copyVideoUrl;
///
/// the selection handler linked to the context menu handler
///
private readonly SelectionHandler _selectionHandler;
///
/// the html container the handler is on
///
private readonly HtmlContainerInt _htmlContainer;
///
/// the last context menu shown
///
private RContextMenu _contextMenu;
///
/// the control that the context menu was shown on
///
private RControl _parentControl;
///
/// the css rectangle that context menu shown on
///
private CssRect _currentRect;
///
/// the css link box that context menu shown on
///
private CssBox _currentLink;
#endregion
///
/// Init context menu items strings.
///
static ContextMenuHandler()
{
if (CultureInfo.CurrentUICulture.Name.StartsWith("fr", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Tout sélectionner";
_copy = "Copier";
_copyLink = "Copier l'adresse du lien";
_openLink = "Ouvrir le lien";
_copyImageLink = "Copier l'URL de l'image";
_copyImage = "Copier l'image";
_saveImage = "Enregistrer l'image sous...";
_openVideo = "Ouvrir la vidéo";
_copyVideoUrl = "Copier l'URL de l'vidéo";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("de", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Alle auswählen";
_copy = "Kopieren";
_copyLink = "Link-Adresse kopieren";
_openLink = "Link öffnen";
_copyImageLink = "Bild-URL kopieren";
_copyImage = "Bild kopieren";
_saveImage = "Bild speichern unter...";
_openVideo = "Video öffnen";
_copyVideoUrl = "Video-URL kopieren";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("it", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Seleziona tutto";
_copy = "Copia";
_copyLink = "Copia indirizzo del link";
_openLink = "Apri link";
_copyImageLink = "Copia URL immagine";
_copyImage = "Copia immagine";
_saveImage = "Salva immagine con nome...";
_openVideo = "Apri il video";
_copyVideoUrl = "Copia URL video";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("es", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Seleccionar todo";
_copy = "Copiar";
_copyLink = "Copiar dirección de enlace";
_openLink = "Abrir enlace";
_copyImageLink = "Copiar URL de la imagen";
_copyImage = "Copiar imagen";
_saveImage = "Guardar imagen como...";
_openVideo = "Abrir video";
_copyVideoUrl = "Copiar URL de la video";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("ru", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Выбрать все";
_copy = "Копировать";
_copyLink = "Копировать адрес ссылки";
_openLink = "Перейти по ссылке";
_copyImageLink = "Копировать адрес изображения";
_copyImage = "Копировать изображение";
_saveImage = "Сохранить изображение как...";
_openVideo = "Открыть видео";
_copyVideoUrl = "Копировать адрес видео";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("sv", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Välj allt";
_copy = "Kopiera";
_copyLink = "Kopiera länkadress";
_openLink = "Öppna länk";
_copyImageLink = "Kopiera bildens URL";
_copyImage = "Kopiera bild";
_saveImage = "Spara bild som...";
_openVideo = "Öppna video";
_copyVideoUrl = "Kopiera video URL";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("hu", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Összes kiválasztása";
_copy = "Másolás";
_copyLink = "Hivatkozás címének másolása";
_openLink = "Hivatkozás megnyitása";
_copyImageLink = "Kép URL másolása";
_copyImage = "Kép másolása";
_saveImage = "Kép mentése másként...";
_openVideo = "Videó megnyitása";
_copyVideoUrl = "Videó URL másolása";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("cs", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Vybrat vše";
_copy = "Kopírovat";
_copyLink = "Kopírovat adresu odkazu";
_openLink = "Otevřít odkaz";
_copyImageLink = "Kopírovat URL snímku";
_copyImage = "Kopírovat snímek";
_saveImage = "Uložit snímek jako...";
_openVideo = "Otevřít video";
_copyVideoUrl = "Kopírovat URL video";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("da", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Vælg alt";
_copy = "Kopiér";
_copyLink = "Kopier link-adresse";
_openLink = "Åbn link";
_copyImageLink = "Kopier billede-URL";
_copyImage = "Kopier billede";
_saveImage = "Gem billede som...";
_openVideo = "Åbn video";
_copyVideoUrl = "Kopier video-URL";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("nl", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Alles selecteren";
_copy = "Kopiëren";
_copyLink = "Link adres kopiëren";
_openLink = "Link openen";
_copyImageLink = "URL Afbeelding kopiëren";
_copyImage = "Afbeelding kopiëren";
_saveImage = "Bewaar afbeelding als...";
_openVideo = "Video openen";
_copyVideoUrl = "URL video kopiëren";
}
else if (CultureInfo.CurrentUICulture.Name.StartsWith("fi", StringComparison.InvariantCultureIgnoreCase))
{
_selectAll = "Valitse kaikki";
_copy = "Kopioi";
_copyLink = "Kopioi linkin osoite";
_openLink = "Avaa linkki";
_copyImageLink = "Kopioi kuvan URL";
_copyImage = "Kopioi kuva";
_saveImage = "Tallena kuva nimellä...";
_openVideo = "Avaa video";
_copyVideoUrl = "Kopioi video URL";
}
else
{
_selectAll = "Select all";
_copy = "Copy";
_copyLink = "Copy link address";
_openLink = "Open link";
_copyImageLink = "Copy image URL";
_copyImage = "Copy image";
_saveImage = "Save image as...";
_openVideo = "Open video";
_copyVideoUrl = "Copy video URL";
}
}
///
/// Init.
///
/// the selection handler linked to the context menu handler
/// the html container the handler is on
public ContextMenuHandler(SelectionHandler selectionHandler, HtmlContainerInt htmlContainer)
{
ArgChecker.AssertArgNotNull(selectionHandler, "selectionHandler");
ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer");
_selectionHandler = selectionHandler;
_htmlContainer = htmlContainer;
}
///
/// Show context menu clicked on given rectangle.
///
/// the parent control to show the context menu on
/// the rectangle that was clicked to show context menu
/// the link that was clicked to show context menu on
public void ShowContextMenu(RControl parent, CssRect rect, CssBox link)
{
try
{
DisposeContextMenu();
_parentControl = parent;
_currentRect = rect;
_currentLink = link;
_contextMenu = _htmlContainer.Adapter.GetContextMenu();
if (rect != null)
{
bool isVideo = false;
if (link != null)
{
isVideo = link is CssBoxFrame && ((CssBoxFrame)link).IsVideo;
var linkExist = !string.IsNullOrEmpty(link.HrefLink);
_contextMenu.AddItem(isVideo ? _openVideo : _openLink, linkExist, OnOpenLinkClick);
if (_htmlContainer.IsSelectionEnabled)
{
_contextMenu.AddItem(isVideo ? _copyVideoUrl : _copyLink, linkExist, OnCopyLinkClick);
}
_contextMenu.AddDivider();
}
if (rect.IsImage && !isVideo)
{
_contextMenu.AddItem(_saveImage, rect.Image != null, OnSaveImageClick);
if (_htmlContainer.IsSelectionEnabled)
{
_contextMenu.AddItem(_copyImageLink, !string.IsNullOrEmpty(_currentRect.OwnerBox.GetAttribute("src")), OnCopyImageLinkClick);
_contextMenu.AddItem(_copyImage, rect.Image != null, OnCopyImageClick);
}
_contextMenu.AddDivider();
}
if (_htmlContainer.IsSelectionEnabled)
{
_contextMenu.AddItem(_copy, rect.Selected, OnCopyClick);
}
}
if (_htmlContainer.IsSelectionEnabled)
{
_contextMenu.AddItem(_selectAll, true, OnSelectAllClick);
}
if (_contextMenu.ItemsCount > 0)
{
_contextMenu.RemoveLastDivider();
_contextMenu.Show(parent, parent.MouseLocation);
}
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to show context menu", ex);
}
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
/// 2
public void Dispose()
{
DisposeContextMenu();
}
#region Private methods
///
/// Dispose of the last used context menu.
///
private void DisposeContextMenu()
{
try
{
if (_contextMenu != null)
_contextMenu.Dispose();
_contextMenu = null;
_parentControl = null;
_currentRect = null;
_currentLink = null;
}
catch
{ }
}
///
/// Handle link click.
///
private void OnOpenLinkClick(object sender, EventArgs eventArgs)
{
try
{
_currentLink.HtmlContainer.HandleLinkClicked(_parentControl, _parentControl.MouseLocation, _currentLink);
}
catch (HtmlLinkClickedException)
{
throw;
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to open link", ex);
}
finally
{
DisposeContextMenu();
}
}
///
/// Copy the href of a link to clipboard.
///
private void OnCopyLinkClick(object sender, EventArgs eventArgs)
{
try
{
_htmlContainer.Adapter.SetToClipboard(_currentLink.HrefLink);
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to copy link url to clipboard", ex);
}
finally
{
DisposeContextMenu();
}
}
///
/// Open save as dialog to save the image
///
private void OnSaveImageClick(object sender, EventArgs eventArgs)
{
try
{
var imageSrc = _currentRect.OwnerBox.GetAttribute("src");
_htmlContainer.Adapter.SaveToFile(_currentRect.Image, Path.GetFileName(imageSrc) ?? "image", Path.GetExtension(imageSrc) ?? "png");
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to save image", ex);
}
finally
{
DisposeContextMenu();
}
}
///
/// Copy the image source to clipboard.
///
private void OnCopyImageLinkClick(object sender, EventArgs eventArgs)
{
try
{
_htmlContainer.Adapter.SetToClipboard(_currentRect.OwnerBox.GetAttribute("src"));
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to copy image url to clipboard", ex);
}
finally
{
DisposeContextMenu();
}
}
///
/// Copy image object to clipboard.
///
private void OnCopyImageClick(object sender, EventArgs eventArgs)
{
try
{
_htmlContainer.Adapter.SetToClipboard(_currentRect.Image);
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to copy image to clipboard", ex);
}
finally
{
DisposeContextMenu();
}
}
///
/// Copy selected text.
///
private void OnCopyClick(object sender, EventArgs eventArgs)
{
try
{
_selectionHandler.CopySelectedHtml();
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to copy text to clipboard", ex);
}
finally
{
DisposeContextMenu();
}
}
///
/// Select all text.
///
private void OnSelectAllClick(object sender, EventArgs eventArgs)
{
try
{
_selectionHandler.SelectAll(_parentControl);
}
catch (Exception ex)
{
_htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to select all text", ex);
}
finally
{
DisposeContextMenu();
}
}
#endregion
}
}