| /* |
| * Copyright (C) 2017 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WI.CanvasTabContentView = class CanvasTabContentView extends WI.ContentBrowserTabContentView |
| { |
| constructor(representedObject) |
| { |
| console.assert(!representedObject || representedObject instanceof WI.Canvas); |
| |
| let tabBarItem = WI.GeneralTabBarItem.fromTabInfo(WI.CanvasTabContentView.tabInfo()); |
| |
| const navigationSidebarPanelConstructor = WI.CanvasSidebarPanel; |
| const detailsSidebarPanelConstructors = [WI.RecordingStateDetailsSidebarPanel, WI.RecordingTraceDetailsSidebarPanel, WI.CanvasDetailsSidebarPanel]; |
| const disableBackForward = true; |
| super("canvas", ["canvas"], tabBarItem, navigationSidebarPanelConstructor, detailsSidebarPanelConstructors, disableBackForward); |
| |
| this._canvasCollection = new WI.CanvasCollection; |
| |
| this._canvasTreeOutline = new WI.TreeOutline; |
| this._canvasTreeOutline.allowsRepeatSelection = true; |
| this._canvasTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._canvasTreeOutlineSelectionDidChange, this); |
| |
| this._overviewTreeElement = new WI.GeneralTreeElement("canvas-overview", WI.UIString("Overview"), null, this._canvasCollection); |
| this._canvasTreeOutline.appendChild(this._overviewTreeElement); |
| |
| this._savedRecordingsTreeElement = new WI.FolderTreeElement(WI.UIString("Saved Recordings"), WI.RecordingCollection); |
| this._savedRecordingsTreeElement.hidden = true; |
| this._overviewTreeElement.appendChild(this._savedRecordingsTreeElement); |
| |
| this._recordShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Space, this._handleSpace.bind(this)); |
| this._recordShortcut.implicitlyPreventsDefault = false; |
| this._recordShortcut.disabled = true; |
| |
| this._recordSingleFrameShortcut = new WI.KeyboardShortcut(WI.KeyboardShortcut.Modifier.Shift, WI.KeyboardShortcut.Key.Space, this._handleSpace.bind(this)); |
| this._recordSingleFrameShortcut.implicitlyPreventsDefault = false; |
| this._recordSingleFrameShortcut.disabled = true; |
| |
| WI.canvasManager.enable(); |
| } |
| |
| static tabInfo() |
| { |
| return { |
| image: "Images/Canvas.svg", |
| title: WI.UIString("Canvas"), |
| }; |
| } |
| |
| static isTabAllowed() |
| { |
| return !!window.CanvasAgent; |
| } |
| |
| // Public |
| |
| treeElementForRepresentedObject(representedObject) |
| { |
| return this._canvasTreeOutline.findTreeElement(representedObject); |
| } |
| |
| get type() |
| { |
| return WI.CanvasTabContentView.Type; |
| } |
| |
| get supportsSplitContentBrowser() |
| { |
| return true; |
| } |
| |
| get managesNavigationSidebarPanel() |
| { |
| return true; |
| } |
| |
| canShowRepresentedObject(representedObject) |
| { |
| return representedObject instanceof WI.Canvas |
| || representedObject instanceof WI.CanvasCollection |
| || representedObject instanceof WI.Recording |
| || representedObject instanceof WI.ShaderProgram; |
| } |
| |
| shown() |
| { |
| super.shown(); |
| |
| this._recordShortcut.disabled = false; |
| this._recordSingleFrameShortcut.disabled = false; |
| |
| if (!this.contentBrowser.currentContentView) |
| this.showRepresentedObject(this._canvasCollection); |
| } |
| |
| hidden() |
| { |
| this._recordShortcut.disabled = true; |
| this._recordSingleFrameShortcut.disabled = true; |
| |
| super.hidden(); |
| } |
| |
| closed() |
| { |
| WI.canvasManager.disable(); |
| |
| super.closed(); |
| } |
| |
| restoreStateFromCookie(cookie) |
| { |
| // FIXME: implement once <https://webkit.org/b/177606> is complete. |
| } |
| |
| saveStateToCookie(cookie) |
| { |
| // FIXME: implement once <https://webkit.org/b/177606> is complete. |
| } |
| |
| async handleFileDrop(files) |
| { |
| await WI.FileUtilities.readJSON(files, (result) => WI.canvasManager.processJSON(result)); |
| } |
| |
| // Protected |
| |
| attached() |
| { |
| super.attached(); |
| |
| WI.canvasManager.addEventListener(WI.CanvasManager.Event.CanvasAdded, this._handleCanvasAdded, this); |
| WI.canvasManager.addEventListener(WI.CanvasManager.Event.CanvasRemoved, this._handleCanvasRemoved, this); |
| WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingSaved, this._handleRecordingSavedOrStopped, this); |
| WI.Canvas.addEventListener(WI.Canvas.Event.RecordingStopped, this._handleRecordingSavedOrStopped, this); |
| |
| let canvases = WI.canvasManager.canvases; |
| |
| for (let canvas of this._canvasCollection) { |
| if (!canvases.includes(canvas)) |
| this._removeCanvas(canvas); |
| } |
| |
| for (let canvas of canvases) { |
| if (!this._canvasCollection.has(canvas)) |
| this._addCanvas(canvas); |
| } |
| |
| this._savedRecordingsTreeElement.removeChildren(); |
| for (let recording of WI.canvasManager.savedRecordings) |
| this._addRecording(recording, {suppressShowRecording: true}); |
| } |
| |
| detached() |
| { |
| WI.Canvas.removeEventListener(null, null, this); |
| WI.canvasManager.removeEventListener(null, null, this); |
| |
| super.detached(); |
| } |
| |
| // Private |
| |
| _addCanvas(canvas) |
| { |
| this._overviewTreeElement.appendChild(new WI.CanvasTreeElement(canvas)); |
| this._canvasCollection.add(canvas); |
| |
| const options = { |
| suppressShowRecording: true, |
| }; |
| |
| for (let recording of canvas.recordingCollection) |
| this._addRecording(recording, options); |
| } |
| |
| _removeCanvas(canvas) |
| { |
| let treeElement = this._canvasTreeOutline.findTreeElement(canvas); |
| console.assert(treeElement, "Missing tree element for canvas.", canvas); |
| |
| const suppressNotification = true; |
| treeElement.deselect(suppressNotification); |
| this._overviewTreeElement.removeChild(treeElement); |
| |
| this._canvasCollection.remove(canvas); |
| |
| let currentContentView = this.contentBrowser.currentContentView; |
| if (currentContentView instanceof WI.CanvasContentView) |
| WI.showRepresentedObject(this._canvasCollection); |
| else if (currentContentView instanceof WI.RecordingContentView && canvas.recordingCollection.has(currentContentView.representedObject)) |
| this.contentBrowser.updateHierarchicalPathForCurrentContentView(); |
| |
| let navigationSidebarPanel = this.navigationSidebarPanel; |
| if (navigationSidebarPanel instanceof WI.CanvasSidebarPanel && navigationSidebarPanel.visible) |
| navigationSidebarPanel.updateRepresentedObjects(); |
| |
| this.showDetailsSidebarPanels(); |
| } |
| |
| _addRecording(recording, options = {}) |
| { |
| if (!recording.source) { |
| const subtitle = null; |
| let recordingTreeElement = new WI.GeneralTreeElement(["recording"], recording.displayName, subtitle, recording); |
| this._savedRecordingsTreeElement.hidden = false; |
| this._savedRecordingsTreeElement.appendChild(recordingTreeElement); |
| } |
| |
| if (!options.suppressShowRecording) |
| this.showRepresentedObject(recording); |
| } |
| |
| _handleCanvasAdded(event) |
| { |
| this._addCanvas(event.data.canvas); |
| } |
| |
| _handleCanvasRemoved(event) |
| { |
| this._removeCanvas(event.data.canvas); |
| } |
| |
| _canvasTreeOutlineSelectionDidChange(event) |
| { |
| let selectedElement = this._canvasTreeOutline.selectedTreeElement; |
| if (!selectedElement) |
| return; |
| |
| let representedObject = selectedElement.representedObject; |
| if (!this.canShowRepresentedObject(representedObject)) { |
| console.assert(false, "Unexpected representedObject.", representedObject); |
| return; |
| } |
| |
| this.showRepresentedObject(representedObject); |
| } |
| |
| _handleRecordingSavedOrStopped(event) |
| { |
| let {recording, initiatedByUser, imported} = event.data; |
| if (!recording) |
| return; |
| |
| let options = {}; |
| |
| // Always show imported recordings. |
| if (recording.source || !imported) |
| options.suppressShowRecording = !initiatedByUser || this.contentBrowser.currentRepresentedObjects.some((representedObject) => representedObject instanceof WI.Recording); |
| |
| this._addRecording(recording, options); |
| } |
| |
| _handleSpace(event) |
| { |
| if (WI.isEventTargetAnEditableField(event)) |
| return; |
| |
| if (!this.navigationSidebarPanel) |
| return; |
| |
| let canvas = this.navigationSidebarPanel.canvas; |
| if (!canvas) |
| return; |
| |
| if (canvas.recordingActive) |
| canvas.stopRecording(); |
| else { |
| let singleFrame = !!event.shiftKey; |
| canvas.startRecording(singleFrame); |
| } |
| |
| event.preventDefault(); |
| } |
| }; |
| |
| WI.CanvasTabContentView.Type = "canvas"; |