diff --git a/apiconcepts/filetypesupport/adding_a_preview_ui_control.md b/apiconcepts/filetypesupport/adding_a_preview_ui_control.md index 41c1e19793..735fdfc4c8 100644 --- a/apiconcepts/filetypesupport/adding_a_preview_ui_control.md +++ b/apiconcepts/filetypesupport/adding_a_preview_ui_control.md @@ -1,211 +1,92 @@ -# Adding a preview UI control -Your filter needs a control that can display the document preview. - -## Add a web browser control - -The static internal preview uses the built-in web browser control in Var:ProductName. See [Modifying the File Type Component Builder](static_modifying_the_file_type_component_builder.md). Other native file formats may require different controls. For example, DOC files use a Microsoft Word Viewer control. - -This sample uses a web browser control again, but this time it adds and configures a custom control instead of reusing the built-in one. - -Start by adding a user control such as **InternalPreviewControl.cs** to your project. Then add a web browser control from the Visual Studio toolbox and name it `webBrowserControl`. - -## Implement the preview control functionality - -To respond to events such as clicking a segment in the editor or scrolling to a segment, implement the following code in your preview control: - -# [C#](#tab/tabid-1) -```cs -using System; -using System.Windows.Forms; -using System.Security.Permissions; -using Sdl.FileTypeSupport.Framework.IntegrationApi; -using Sdl.FileTypeSupport.Framework.NativeApi; - -namespace Sdk.FileTypeSupport.Samples.SimpleText.Preview +# Adding a Preview UI Control + +> [!WARNING] +> **Breaking change in Var:ProductName 2026** +> +> File types no longer provide their own preview UI controls. The methods +> `IFileTypeDefinition.BuildPreviewControl` and +> `IFileTypeComponentBuilder.BuildPreviewControl` are **deprecated and no +> longer called by Var:ProductName**. Custom `UserControl` classes (such as +> `InternalPreviewControl.cs`) and their companion controller classes (such +> as `InternalPreviewController.cs`) are not needed for file types targeting +> Var:ProductName 2026 or later. +> +> If you maintain an existing file type that implements these methods, they +> will be silently ignored at runtime. See [Preview API changes in Trados +> Var:ProductName 2026](preview_api_changes_quantum.md) for the migration checklist. + +## Overview + +Starting with Var:ProductName 2026, Var:ProductName ships a set of +**built-in preview UIs**. Your file type no longer builds or registers a +custom control. Instead, it declares which built-in UI it wants by +referencing a recognised **Preview ID** in its `PreviewSet` definition, and +Var:ProductName handles the rest. + +Your filter is still responsible for generating the preview *content* — the +output file written to the temporary folder. How that content is displayed +is now entirely managed by Var:ProductName. + +## Built-in Preview IDs + +Use one of the following IDs when configuring your `PreviewSet`: + +| Preview ID | Description | +|---|---| +| `HtmlSingleFilePreview` | Renders an HTML file. Can preview source or target individually. | +| `HtmlSideBySidePreview` | Renders source and target side by side. Content must be HTML. | +| `ExternalPreview` | Opens the preview file in the application registered in the OS for that file extension. | +| `ExternalHtml` | Opens the preview file in the default browser. | + +> [!NOTE] +> Using a preview UI that is not in this list is not yet supported in Var:ProductName +> 2026. Third-party preview controls cannot be registered. + +## Register a built-in preview in the File Type Component Builder + +The following example registers `HtmlSingleFilePreview` for both source and +target: + +```csharp +IPreviewSet internalPreviewSet = previewFactory.CreatePreviewSet(); +internalPreviewSet.Id = new PreviewSetId("InternalPreview"); +internalPreviewSet.Name = new LocalizableString(Resources.InternalPreview_Name); + +// Source preview +IControlPreviewType sourcePreviewType = + previewFactory.CreatePreviewType() as IControlPreviewType; +if (sourcePreviewType != null) { - [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] - [System.Runtime.InteropServices.ComVisibleAttribute(true)] - public partial class InternalPreviewControl : UserControl - { - string _activeSegId = String.Empty; - string _jumpparagraphID = String.Empty; - string _jumpsegmentID = String.Empty; - bool _segmentSelectedFromBrowser = false; - - - public event PreviewControlHandler WindowSelectionChanged; - - public InternalPreviewControl() - { - InitializeComponent(); - //set the properties of the webbrowser component - webBrowserControl.AllowWebBrowserDrop = false; - webBrowserControl.IsWebBrowserContextMenuEnabled = false; - webBrowserControl.WebBrowserShortcutsEnabled = false; - webBrowserControl.ScriptErrorsSuppressed = true; - webBrowserControl.AllowNavigation = false; - webBrowserControl.ObjectForScripting = this; - webBrowserControl.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowserControl_DocumentCompleted); - } - - void webBrowserControl_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) - { - ScrollToElement(_activeSegId); - - //set the CSS style for the curently selected segment - webBrowserControl.Document.InvokeScript("setActiveStyle", new String[] { _activeSegId }); - } - - protected void FireWindowSelectionChanged() - { - if (WindowSelectionChanged != null) - { - WindowSelectionChanged(null); - } - } - - /// - /// open file for preview - /// - /// - public void OpenTarget(string fileName) - { - if (this.InvokeRequired) - { - this.Invoke(new System.Action(OpenTarget), fileName); - } - else - { - webBrowserControl.Navigate(fileName); - webBrowserControl.Refresh(); - } - } - - public void Close() - { - // The Filter Framework takes care of cleaning up temporary files. - } - - /// - /// construct a segment reference from _jumpparagraphID and _jumpsegmentID, - /// which is returned when user clicks the corresponding segment in the preview control - /// - /// - public SegmentReference GetSelectedSegment() - { - if (_jumpsegmentID != null && _jumpsegmentID != String.Empty) - { - SegmentReference segRef = new SegmentReference(default(FileId), new ParagraphUnitId(_jumpparagraphID), new SegmentId(_jumpsegmentID)); - return segRef; - } - return null; - } - - /// - /// public method that is called from the preview control - /// when a segment has been selected - /// - /// - public void SelectSegment(string paragraphUnitID, string segmentID) - { - // set global variables for jumping into clicked segment - _jumpparagraphID = paragraphUnitID; - _jumpsegmentID = segmentID; - - _segmentSelectedFromBrowser = true; - FireWindowSelectionChanged(); - } - - /// - /// scroll to the active segment inside the control - /// - /// - private void ScrollToElement(String elemName) - { - if (webBrowserControl.Document != null) - { - HtmlDocument doc = webBrowserControl.Document; - HtmlElementCollection elems = doc.All.GetElementsByName(elemName); - if (elems != null && elems.Count > 0) - { - HtmlElement elem = elems[0]; - - elem.ScrollIntoView(true); - } - } - } - - - /// - /// called when segment is confirmed and Trados Studio jumps into next segment - /// - public void JumpToActiveElement() - { - if (this.InvokeRequired) - { - this.Invoke(new MethodInvoker(JumpToActiveElement)); - } - } - - - /// - /// scroll to and highlight active segment in the preview control - /// - /// - public void ScrollToSegment(SegmentReference segment) - { - if (this.InvokeRequired) - { - this.Invoke(new System.Action(ScrollToSegment), segment); - } - else - { - if (!_segmentSelectedFromBrowser) - { - ScrollToElement(segment.SegmentId.Id); - - // handle situations in which the document was opened - // and no active segment has been set yet. - if (_activeSegId == null || _activeSegId == "") - { - _activeSegId = segment.SegmentId.Id; - // select the CSS style for the curently selected segment - webBrowserControl.Document.InvokeScript("setActiveStyle", new String[] { segment.SegmentId.Id }); - } - } - - if (_activeSegId != segment.SegmentId.Id) - { - // reset the CSS style back from active to normal for the previously selected segment - if (_activeSegId != null || _activeSegId == "") - { - webBrowserControl.Document.InvokeScript("setNormalStyle", new String[] { _activeSegId }); - } - // set the CSS style for the curently selected segment - webBrowserControl.Document.InvokeScript("setActiveStyle", new String[] { segment.SegmentId.Id }); - } - - // set the active segment id - _activeSegId = segment.SegmentId.Id; - - if (_segmentSelectedFromBrowser) - { - _segmentSelectedFromBrowser = false; - } - } - - } - } + sourcePreviewType.SourceGeneratorId = new GeneratorId("PreviewGenerator"); + sourcePreviewType.SingleFilePreviewControlId = + new PreviewControlId("HtmlSingleFilePreview"); + internalPreviewSet.Source = sourcePreviewType; } + +// Target preview +IControlPreviewType targetPreviewType = + previewFactory.CreatePreviewType() as IControlPreviewType; +if (targetPreviewType != null) +{ + targetPreviewType.TargetGeneratorId = new GeneratorId("PreviewGenerator"); + targetPreviewType.SingleFilePreviewControlId = + new PreviewControlId("HtmlSingleFilePreview"); + internalPreviewSet.Target = targetPreviewType; +} + +previewFactory.GetPreviewSets(null).Add(internalPreviewSet); ``` + +Replace `"HtmlSingleFilePreview"` with whichever built-in ID best matches +the preview content your generator produces. ## See also - + +- [Preview API changes in Var:ProductName 2026](preview_api_changes.md) +- [Implementing an External File Preview](implementing_an_external_file_preview.md) - [Modifying the File Type Component Builder](static_modifying_the_file_type_component_builder.md) -- [Adding a Preview Controller](adding_a_preview_controller.md) - ->[!NOTE] -> -> This content may be out-of-date. To check the latest information on this topic, inspect the libraries using the Visual Studio Object Browser. +- [Studio Preview UI](https://rws-dev.atlassian.net/wiki/spaces/LTSTUDIO/pages/1989869850) + (internal Confluence reference for built-in preview UI components) + diff --git a/apiconcepts/filetypesupport/implementing_an_external_file_preview.md b/apiconcepts/filetypesupport/implementing_an_external_file_preview.md index 3aede2a7ca..222d87d318 100644 --- a/apiconcepts/filetypesupport/implementing_an_external_file_preview.md +++ b/apiconcepts/filetypesupport/implementing_an_external_file_preview.md @@ -1,75 +1,79 @@ -# Implementing an External File Preview - -This section explains how to add a simple document preview that uses Windows Notepad. - -## Extend the File Type Component Builder - -Enable the file type plug-in to generate an ad-hoc preview in an external application. This lets users view the file in its native format. - -For example, when users preview DOC files, Var:ProductName launches Microsoft Word as the external preview application. Because this sample uses a simple text format, Notepad works well as the external preview application. - -The sample file type plug-in already contains the logic required to generate an external preview. The file writer class that you created in the previous chapter provides that logic. See [Implementing the File Writer](implementing_the_file_writer.md). To enable the preview, register the external preview application in the File Type Component Builder. - -First, add the name of the preview application to the resource file in your project properties. Users will see this name when they access the external preview command in Var:ProductName. -![ExternalPreview_Name](images/ExternalPreview_Name.jpg) - -Now add the following method to the File Type Component Builder. The example references the external preview application name from resources. It also enables the external preview for both source and target content. - -# [C#](#tab/tabid-1) -```cs +# Implementing an External File Preview + +> [!WARNING] +> **Breaking change in Var:ProductName 2026** +> +> The `BuildPreviewApplication` method on `IFileTypeComponentBuilder` is +> **deprecated and no longer called by Var:ProductName**. The +> `GenericExternalPreviewApplication` class and the +> `Sdl.FileTypeSupport.Framework.PreviewControls` assembly reference are no +> longer needed. Remove them from any file type that targets Var:ProductName 2026 or +> later. +> +> The `PreviewSet` registration pattern shown below still applies, but the +> Preview ID must now be one of the **built-in IDs** recognised by Var:ProductName. +> See [Preview API changes in Trados Var:ProductName 2026](preview_api_changes.md) +> for the full list of built-in IDs and a migration checklist. + +## Overview + +Var:ProductName can open a preview of the translated file in an external +application. The application that is launched is determined automatically by +the file extension registered in the operating system — the file type plugin +no longer specifies a path to an executable. + +The application logic needed to generate the preview file is already +provided by your file writer class. All you need to do is register the +external preview in the File Type Component Builder, using the built-in +`ExternalPreview` ID. + +## Register the external preview + +Add the following code to your File Type Component Builder to register an +external preview for both source and target: + +```csharp IPreviewSet externalPreviewSet = previewFactory.CreatePreviewSet(); -externalPreviewSet.Id = new PreviewSetId("ExternalPreview"); +externalPreviewSet.Id = new PreviewSetId("ExternalPreview"); externalPreviewSet.Name = new LocalizableString(Resources.ExternalPreview_Name); - -IApplicationPreviewType sourceAppPreviewType = previewFactory.CreatePreviewType() as IApplicationPreviewType; - + +IApplicationPreviewType sourceAppPreviewType = + previewFactory.CreatePreviewType() as IApplicationPreviewType; if (sourceAppPreviewType != null) { sourceAppPreviewType.SourceGeneratorId = new GeneratorId("DefaultPreview"); - sourceAppPreviewType.SingleFilePreviewApplicationId = new PreviewApplicationId("ExternalPreview"); + sourceAppPreviewType.SingleFilePreviewApplicationId = + new PreviewApplicationId("ExternalPreview"); externalPreviewSet.Source = sourceAppPreviewType; } - -IApplicationPreviewType targetAppPreviewType = previewFactory.CreatePreviewType() as IApplicationPreviewType; + +IApplicationPreviewType targetAppPreviewType = + previewFactory.CreatePreviewType() as IApplicationPreviewType; if (targetAppPreviewType != null) { targetAppPreviewType.TargetGeneratorId = new GeneratorId("DefaultPreview"); - targetAppPreviewType.SingleFilePreviewApplicationId = new PreviewApplicationId("ExternalPreview"); + targetAppPreviewType.SingleFilePreviewApplicationId = + new PreviewApplicationId("ExternalPreview"); externalPreviewSet.Target = targetAppPreviewType; } - + previewFactory.GetPreviewSets(null).Add(externalPreviewSet); ``` -*** - -Now update the File Type Component Builder to include the external preview. In this example, `GenericExteralPreviewApplication` launches Microsoft Notepad. - -# [C#](#tab/tabid-2) -```cs -public IAbstractPreviewApplication BuildPreviewApplication(string name) -{ - if (name == "PreviewApplication_ExternalPreview") - { - Sdl.FileTypeSupport.Framework.PreviewControls.GenericExteralPreviewApplication genericExteralPreviewApplication = new Sdl.FileTypeSupport.Framework.PreviewControls.GenericExteralPreviewApplication(); - genericExteralPreviewApplication.ApplicationPath = @"c:\Windows\System32\notepad.exe"; - return genericExteralPreviewApplication; - } - return null; -} -``` -*** - -Add an assembly reference to `Sdl.FileTypeSupport.Framework.PreviewControls`. - ->[!NOTE] -> -> You can also pass an empty string to the `ApplicationPath` property. In that case, the external preview calls the application that the operating system registers for that file type. - -When you open **File** > **View In** in Var:ProductName, you should now see the following option: - -![PreviewApplication](images/PreviewApplication.jpg) - ->[!NOTE] -> -> This content may be out-of-date. To check the latest information on this topic, inspect the libraries using the Visual Studio Object Browser. + +`ExternalPreview` is a built-in Var:ProductName preview ID. When a user triggers the +preview, Var:ProductName opens the generated file in the application registered in +the OS for that file extension — the same behaviour that the old +`ApplicationPath = ""` shortcut produced, now as the only and default +behaviour. + +> [!NOTE] +> You do not need to add a reference to +> `Sdl.FileTypeSupport.Framework.PreviewControls`, and you do not need to +> implement `BuildPreviewApplication`. Both are deprecated in Var:ProductName 2026. + +## See also + +- [Preview API changes in Trados Studio 2026](preview_api_changes.md) +- [Adding a Preview UI Control](adding_a_preview_ui_control.md) +- [Implementing the File Writer](implementing_the_file_writer.md) diff --git a/apiconcepts/filetypesupport/preview_api_changes.md b/apiconcepts/filetypesupport/preview_api_changes.md new file mode 100644 index 0000000000..d97d6e5515 --- /dev/null +++ b/apiconcepts/filetypesupport/preview_api_changes.md @@ -0,0 +1,94 @@ + +# Preview API changes in Var:ProductName 2026 + +Var:ProductName 2026 changes the way file type plugins integrate +with the preview subsystem. This page summarises what has changed, why, and +what you need to do if you maintain an existing file type plugin. + +## What changed + +Previously, each file type was responsible for supplying its own preview UI. +Plugins did this by implementing `BuildPreviewControl` or +`BuildPreviewApplication` on the File Type Component Builder and returning a +custom `UserControl` or a `GenericExternalPreviewApplication` instance. + +Starting with Var:ProductName 2026, **Var:ProductName ships a set of built-in preview UIs**. +File types declare which built-in UI they want by placing a recognised +Preview ID in their `PreviewSet` definition. Var:ProductName maps that ID to the +corresponding control at runtime. Plugins no longer build, own, or register +preview UI components. + +## Deprecated API surface + +The following methods are **deprecated as of Var:ProductName 2026** and are no longer +called by the host application: + +| Deprecated member | Previously used for | +|---|---| +| `IFileTypeDefinition.BuildPreviewControl` | Returning a custom internal preview `UserControl` | +| `IFileTypeDefinition.BuildPreviewApplication` | Returning a custom external preview application | +| `IFileTypeComponentBuilder.BuildPreviewControl` | Same as above, on the component builder | +| `IFileTypeComponentBuilder.BuildPreviewApplication` | Same as above, on the component builder | + +Implementing these methods in a plugin targeting Var:ProductName 2026 is harmless — +they are ignored at runtime — but they should be removed to keep the +codebase clean. + +## Built-in Preview IDs + +Your `PreviewSet` must reference one of the following IDs. Var:ProductName maps each +ID to a built-in control: + +| Preview ID | Description | +|---|---| +| `HtmlSingleFilePreview` | Renders an HTML file. Source or target individually. | +| `HtmlSideBySidePreview` | Renders source and target side by side. Content must be HTML. | +| `ExternalPreview` | Opens in an external application based on the OS file-extension registration. | +| `ExternalHtml` | Opens in the default browser. | + +> [!NOTE] +> Using a Preview ID that is not in this list is not yet supported. Custom +> third-party preview UIs cannot be registered in Var:ProductName 2026. + +## Migration checklist + +Use this checklist when updating an existing file type plugin to target +Var:ProductName 2026. + +### Internal (control-based) previews + +- Delete your custom `UserControl` class (for example, + `InternalPreviewControl.cs`). +- Delete your preview controller class (for example, + `InternalPreviewController.cs`). +- Remove the `BuildPreviewControl` method from your File Type Component + Builder. +- In your `PreviewSet` definition, replace any custom `PreviewControlId` + value (for example, `"InternalNavigablePreview"`) with the appropriate + built-in ID (`"HtmlSingleFilePreview"` or `"HtmlSideBySidePreview"`). +### External (application-based) previews + +- Remove the `BuildPreviewApplication` method from your File Type + Component Builder. +- Delete any `GenericExternalPreviewApplication` instantiation and its + `ApplicationPath` assignment. +- Remove the assembly reference to + `Sdl.FileTypeSupport.Framework.PreviewControls` if it is no longer used + elsewhere. +- Confirm your `PreviewSet` uses `new PreviewApplicationId("ExternalPreview")`. + The OS will determine which application opens the file; no executable path + is required. +### What to keep + +- Your **preview generator** (`IFileGenerator` implementation) is unchanged. + The way preview *content* is produced has not changed — only the way it is + *displayed*. +- The `PreviewSet` creation and registration pattern itself is unchanged. + Only the IDs used inside it need to be updated. +## Further reading + +- [Adding a Preview UI Control](adding_a_preview_ui_control.md) +- [Implementing an External File Preview](implementing_an_external_file_preview.md) +- [Studio Preview UI](https://rws-dev.atlassian.net/wiki/spaces/LTSTUDIO/pages/1989869850) + (internal Confluence reference — authoritative technical detail on + built-in preview UI components) diff --git a/apiconcepts/toc.yml b/apiconcepts/toc.yml index 75efd4bcd7..2b626c695d 100644 --- a/apiconcepts/toc.yml +++ b/apiconcepts/toc.yml @@ -107,6 +107,8 @@ href: filetypesupport/implementing_the_file_writer.md - name: Implementing File Preview Functionality items: + - name: Preview API Changes + href: filetypesupport/preview_api_changes.md - name: Implementing an External File Preview href: filetypesupport/implementing_an_external_file_preview.md - name: Implementing an Internal Preview