Browse Source

Rename imagewidget -> imageviewer.

Brian E. Granger 8 years ago
parent
commit
b9ba94d8ba

+ 3 - 3
design/imagewidget.md

@@ -1,9 +1,9 @@
-# Design of the imagewidget plugin
-This document describes the design of the imagewidget plugin. This document illustrates how our research on personas and other solutions translates into the design decisions made to improve the imagewidget plugin.
+# Design of the imageviewer plugin
+This document describes the design of the imageviewer plugin. This document illustrates how our research on personas and other solutions translates into the design decisions made to improve the imageviewer plugin.
 
 # Personas
 ### Jackie Lair
-Jackie Lair is an experienced data scientist who is familiar with JupyterLab and uses it regularly. She uses the imagewidget to compare MRI scans alongside her code and write programs that outputs the information found in the MRI scans. 
+Jackie Lair is an experienced data scientist who is familiar with JupyterLab and uses it regularly. She uses the imageviewer to compare MRI scans alongside her code and write programs that outputs the information found in the MRI scans. 
 
 **Goal:** To be able to manipulate images in JupyterLab to view alongside other tabs and support data analysis.
 

+ 1 - 1
examples/app/index.js

@@ -24,7 +24,7 @@ var mods = [
   require('@jupyterlab/faq-extension'),
   require('@jupyterlab/filebrowser-extension'),
   require('@jupyterlab/help-extension'),
-  require('@jupyterlab/imagewidget-extension'),
+  require('@jupyterlab/imageviewer-extension'),
   require('@jupyterlab/inspector-extension'),
   require('@jupyterlab/landing-extension'),
   require('@jupyterlab/launcher-extension'),

+ 1 - 1
examples/app/package.json

@@ -21,7 +21,7 @@
     "@jupyterlab/faq-extension": "^0.4.0",
     "@jupyterlab/filebrowser-extension": "^0.4.0",
     "@jupyterlab/help-extension": "^0.4.0",
-    "@jupyterlab/imagewidget-extension": "^0.4.0",
+    "@jupyterlab/imageviewer-extension": "^0.4.0",
     "@jupyterlab/inspector-extension": "^0.4.0",
     "@jupyterlab/landing-extension": "^0.4.0",
     "@jupyterlab/launcher-extension": "^0.4.0",

+ 2 - 2
jupyterlab/package.json

@@ -20,7 +20,7 @@
     "@jupyterlab/faq-extension": "^0.4.0",
     "@jupyterlab/filebrowser-extension": "^0.4.0",
     "@jupyterlab/help-extension": "^0.4.0",
-    "@jupyterlab/imagewidget-extension": "^0.4.0",
+    "@jupyterlab/imageviewer-extension": "^0.4.0",
     "@jupyterlab/inspector-extension": "^0.4.0",
     "@jupyterlab/landing-extension": "^0.4.0",
     "@jupyterlab/launcher-extension": "^0.4.0",
@@ -65,7 +65,7 @@
       "@jupyterlab/faq-extension",
       "@jupyterlab/filebrowser-extension",
       "@jupyterlab/help-extension",
-      "@jupyterlab/imagewidget-extension",
+      "@jupyterlab/imageviewer-extension",
       "@jupyterlab/inspector-extension",
       "@jupyterlab/landing-extension",
       "@jupyterlab/launcher-extension",

+ 2 - 2
jupyterlab/package.template.json

@@ -20,7 +20,7 @@
     "@jupyterlab/faq-extension": "^0.4.0",
     "@jupyterlab/filebrowser-extension": "^0.4.0",
     "@jupyterlab/help-extension": "^0.4.0",
-    "@jupyterlab/imagewidget-extension": "^0.4.0",
+    "@jupyterlab/imageviewer-extension": "^0.4.0",
     "@jupyterlab/inspector-extension": "^0.4.0",
     "@jupyterlab/landing-extension": "^0.4.0",
     "@jupyterlab/launcher-extension": "^0.4.0",
@@ -65,7 +65,7 @@
       "@jupyterlab/faq-extension",
       "@jupyterlab/filebrowser-extension",
       "@jupyterlab/help-extension",
-      "@jupyterlab/imagewidget-extension",
+      "@jupyterlab/imageviewer-extension",
       "@jupyterlab/inspector-extension",
       "@jupyterlab/landing-extension",
       "@jupyterlab/launcher-extension",

+ 3 - 3
jupyterlab/src/main.ts

@@ -46,8 +46,8 @@ import * as filebrowserExtension
 import * as helpExtension
   from '@jupyterlab/help-extension';
 
-import * as imagewidgetExtension
-  from '@jupyterlab/imagewidget-extension';
+import * as imageviewerExtension
+  from '@jupyterlab/imageviewer-extension';
 
 import * as inspectorExtension
   from '@jupyterlab/inspector-extension';
@@ -103,7 +103,7 @@ const mods: JupyterLab.IPluginModule[] = [
   faqExtension,
   filebrowserExtension,
   helpExtension,
-  imagewidgetExtension,
+  imageviewerExtension,
   inspectorExtension,
   landingExtension,
   launchExtension,

+ 2 - 2
packages/all-packages/package.json

@@ -40,8 +40,8 @@
     "@jupyterlab/filebrowser": "^0.4.0",
     "@jupyterlab/filebrowser-extension": "^0.4.0",
     "@jupyterlab/help-extension": "^0.4.0",
-    "@jupyterlab/imagewidget": "^0.4.0",
-    "@jupyterlab/imagewidget-extension": "^0.4.0",
+    "@jupyterlab/imageviewer": "^0.4.0",
+    "@jupyterlab/imageviewer-extension": "^0.4.0",
     "@jupyterlab/inspector": "^0.4.0",
     "@jupyterlab/inspector-extension": "^0.4.0",
     "@jupyterlab/landing-extension": "^0.4.0",

+ 2 - 2
packages/all-packages/src/index.ts

@@ -27,8 +27,8 @@ import "@jupyterlab/faq-extension";
 import "@jupyterlab/filebrowser";
 import "@jupyterlab/filebrowser-extension";
 import "@jupyterlab/help-extension";
-import "@jupyterlab/imagewidget";
-import "@jupyterlab/imagewidget-extension";
+import "@jupyterlab/imageviewer";
+import "@jupyterlab/imageviewer-extension";
 import "@jupyterlab/inspector";
 import "@jupyterlab/inspector-extension";
 import "@jupyterlab/landing-extension";

+ 1 - 1
packages/default-theme/package.json

@@ -29,7 +29,7 @@
     "@jupyterlab/faq-extension": "^0.4.0",
     "@jupyterlab/filebrowser": "^0.4.0",
     "@jupyterlab/help-extension": "^0.4.0",
-    "@jupyterlab/imagewidget": "^0.4.0",
+    "@jupyterlab/imageviewer": "^0.4.0",
     "@jupyterlab/inspector": "^0.4.0",
     "@jupyterlab/landing-extension": "^0.4.0",
     "@jupyterlab/launcher": "^0.4.0",

+ 1 - 1
packages/default-theme/style/index.css

@@ -23,7 +23,7 @@
 @import url('~@jupyterlab/faq-extension/style/index.css');
 @import url('~@jupyterlab/filebrowser/style/index.css');
 @import url('~@jupyterlab/help-extension/style/index.css');
-@import url('~@jupyterlab/imagewidget/style/index.css');
+@import url('~@jupyterlab/imageviewer/style/index.css');
 @import url('~@jupyterlab/inspector/style/index.css');
 @import url('~@jupyterlab/landing-extension/style/index.css');
 @import url('~@jupyterlab/launcher/style/index.css');

+ 2 - 2
packages/imageviewer-extension/package.json

@@ -1,5 +1,5 @@
 {
-  "name": "@jupyterlab/imagewidget-extension",
+  "name": "@jupyterlab/imageviewer-extension",
   "version": "0.4.0",
   "description": "JupyterLab - Image Widget Extension",
   "main": "lib/index.js",
@@ -15,7 +15,7 @@
     "@jupyterlab/application": "^0.4.0",
     "@jupyterlab/apputils": "^0.4.0",
     "@jupyterlab/docregistry": "^0.4.0",
-    "@jupyterlab/imagewidget": "^0.4.0"
+    "@jupyterlab/imageviewer": "^0.4.0"
   },
   "devDependencies": {
     "rimraf": "^2.5.2",

+ 4 - 4
packages/imageviewer-extension/src/index.ts

@@ -15,7 +15,7 @@ import {
 
 import {
   ImageViewer, ImageViewerFactory, IImageTracker
-} from '@jupyterlab/imagewidget';
+} from '@jupyterlab/imageviewer';
 
 
 /**
@@ -23,13 +23,13 @@ import {
  */
 namespace CommandIDs {
   export
-  const zoomIn = 'imagewidget:zoom-in';
+  const zoomIn = 'imageviewer:zoom-in';
 
   export
-  const zoomOut = 'imagewidget:zoom-out';
+  const zoomOut = 'imageviewer:zoom-out';
 
   export
-  const resetZoom = 'imagewidget:reset-zoom';
+  const resetZoom = 'imageviewer:reset-zoom';
 };
 
 

+ 1 - 1
packages/imageviewer/package.json

@@ -1,5 +1,5 @@
 {
-  "name": "@jupyterlab/imagewidget",
+  "name": "@jupyterlab/imageviewer",
   "version": "0.4.0",
   "description": "JupyterLab - Image Widget",
   "main": "lib/index.js",

+ 3 - 3
packages/imageviewer/src/index.ts

@@ -41,17 +41,17 @@ const IImageTracker = new Token<IImageTracker>('jupyter.services.image-tracker')
  */
 export
 function addDefaultCommands(tracker: IImageTracker, commands: CommandRegistry) {
-  commands.addCommand('imagewidget:zoom-in', {
+  commands.addCommand('imageviewer:zoom-in', {
     execute: zoomIn,
     label: 'Zoom In'
   });
 
-  commands.addCommand('imagewidget:zoom-out', {
+  commands.addCommand('imageviewer:zoom-out', {
     execute: zoomOut,
     label: 'Zoom Out'
   });
 
-  commands.addCommand('imagewidget:reset-zoom', {
+  commands.addCommand('imageviewer:reset-zoom', {
     execute: resetZoom,
     label: 'Reset Zoom'
   });

+ 1 - 1
packages/imageviewer/src/widget.ts

@@ -14,7 +14,7 @@ import {
 } from '@jupyterlab/docregistry';
 
 /**
- * The class name added to a imagewidget.
+ * The class name added to a imageviewer.
  */
 const IMAGE_CLASS = 'jp-ImageViewer';
 

+ 99 - 0
packages/imagewidget-extension/src/index.ts

@@ -0,0 +1,99 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  JupyterLab, JupyterLabPlugin
+} from '@jupyterlab/application';
+
+import {
+  ICommandPalette, ILayoutRestorer, InstanceTracker
+} from '@jupyterlab/apputils';
+
+import {
+  IDocumentRegistry
+} from '@jupyterlab/docregistry';
+
+import {
+  ImageViewer, ImageViewerFactory, IImageTracker
+} from '@jupyterlab/imageviewer';
+
+
+/**
+ * The command IDs used by the image widget plugin.
+ */
+namespace CommandIDs {
+  export
+  const zoomIn = 'imageviewer:zoom-in';
+
+  export
+  const zoomOut = 'imageviewer:zoom-out';
+
+  export
+  const resetZoom = 'imageviewer:reset-zoom';
+};
+
+
+/**
+ * The list of file extensions for images.
+ */
+const EXTENSIONS = ['.png', '.gif', '.jpeg', '.jpg', '.svg', '.bmp', '.ico',
+  '.xbm', '.tiff', '.tif'];
+
+/**
+ * The name of the factory that creates image widgets.
+ */
+const FACTORY = 'Image';
+
+/**
+ * The image file handler extension.
+ */
+const plugin: JupyterLabPlugin<IImageTracker> = {
+  activate,
+  id: 'jupyter.extensions.image-handler',
+  provides: IImageTracker,
+  requires: [IDocumentRegistry, ICommandPalette, ILayoutRestorer],
+  autoStart: true
+};
+
+
+/**
+ * Export the plugin as default.
+ */
+export default plugin;
+
+
+/**
+ * Activate the image widget extension.
+ */
+function activate(app: JupyterLab, registry: IDocumentRegistry, palette: ICommandPalette, restorer: ILayoutRestorer): IImageTracker {
+  const namespace = 'image-widget';
+  const factory = new ImageViewerFactory({
+    name: FACTORY,
+    modelName: 'base64',
+    fileExtensions: EXTENSIONS,
+    defaultFor: EXTENSIONS
+  });
+  const { shell } = app;
+  const tracker = new InstanceTracker<ImageViewer>({ namespace, shell });
+
+  // Handle state restoration.
+  restorer.restore(tracker, {
+    command: 'file-operations:open',
+    args: widget => ({ path: widget.context.path, factory: FACTORY }),
+    name: widget => widget.context.path
+  });
+
+  registry.addWidgetFactory(factory);
+
+  factory.widgetCreated.connect((sender, widget) => {
+    // Notify the instance tracker if restore data needs to update.
+    widget.context.pathChanged.connect(() => { tracker.save(widget); });
+    tracker.add(widget);
+  });
+
+  let category = 'Image Widget';
+  [CommandIDs.zoomIn, CommandIDs.zoomOut, CommandIDs.resetZoom]
+    .forEach(command => { palette.addItem({ command, category }); });
+
+  return tracker;
+}

+ 90 - 0
packages/imagewidget/src/index.ts

@@ -0,0 +1,90 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  CommandRegistry
+} from '@phosphor/commands';
+
+import {
+  Token
+} from '@phosphor/coreutils';
+
+import {
+  IInstanceTracker
+} from '@jupyterlab/apputils';
+
+import {
+  ImageViewer
+} from './widget';
+
+export * from './widget';
+
+
+/**
+ * A class that tracks editor widgets.
+ */
+export
+interface IImageTracker extends IInstanceTracker<ImageViewer> {}
+
+
+/* tslint:disable */
+/**
+ * The editor tracker token.
+ */
+export
+const IImageTracker = new Token<IImageTracker>('jupyter.services.image-tracker');
+/* tslint:enable */
+
+
+/**
+ * Add the default commands for the image widget.
+ */
+export
+function addDefaultCommands(tracker: IImageTracker, commands: CommandRegistry) {
+  commands.addCommand('imageviewer:zoom-in', {
+    execute: zoomIn,
+    label: 'Zoom In'
+  });
+
+  commands.addCommand('imageviewer:zoom-out', {
+    execute: zoomOut,
+    label: 'Zoom Out'
+  });
+
+  commands.addCommand('imageviewer:reset-zoom', {
+    execute: resetZoom,
+    label: 'Reset Zoom'
+  });
+
+  function zoomIn(): void {
+    let widget = tracker.currentWidget;
+    if (!widget) {
+      return;
+    }
+    if (widget.scale > 1) {
+      widget.scale += .5;
+    } else {
+      widget.scale *= 2;
+    }
+  }
+
+  function zoomOut(): void {
+    let widget = tracker.currentWidget;
+    if (!widget) {
+      return;
+    }
+    if (widget.scale > 1) {
+      widget.scale -= .5;
+    } else {
+      widget.scale /= 2;
+    }
+  }
+
+  function resetZoom(): void {
+    let widget = tracker.currentWidget;
+    if (!widget) {
+      return;
+    }
+    widget.scale = 1;
+  }
+}

+ 140 - 0
packages/imagewidget/src/widget.ts

@@ -0,0 +1,140 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  Message
+} from '@phosphor/messaging';
+
+import {
+  Widget
+} from '@phosphor/widgets';
+
+import {
+  ABCWidgetFactory, DocumentRegistry
+} from '@jupyterlab/docregistry';
+
+/**
+ * The class name added to a imageviewer.
+ */
+const IMAGE_CLASS = 'jp-ImageViewer';
+
+
+/**
+ * A widget for images.
+ */
+export
+class ImageViewer extends Widget {
+  /**
+   * Construct a new image widget.
+   */
+  constructor(context: DocumentRegistry.Context) {
+    super({ node: Private.createNode() });
+    this._context = context;
+    this.node.tabIndex = -1;
+    this.addClass(IMAGE_CLASS);
+
+    this._onTitleChanged();
+    context.pathChanged.connect(this._onTitleChanged, this);
+
+    context.ready.then(() => {
+      this.update();
+      context.model.contentChanged.connect(this.update, this);
+      context.fileChanged.connect(this.update, this);
+    });
+  }
+
+  /**
+   * The image widget's context.
+   */
+  get context(): DocumentRegistry.Context {
+    return this._context;
+  }
+
+  /**
+   * The scale factor for the image.
+   */
+  get scale(): number {
+    return this._scale;
+  }
+  set scale(value: number) {
+    if (value === this._scale) {
+      return;
+    }
+    this._scale = value;
+    let scaleNode = this.node.querySelector('div') as HTMLElement;
+    let transform: string;
+    transform = `scale(${value})`;
+    scaleNode.style.transform = transform;
+  }
+
+  /**
+   * Dispose of the resources used by the widget.
+   */
+  dispose(): void {
+    this._context = null;
+    super.dispose();
+  }
+
+  /**
+   * Handle `update-request` messages for the widget.
+   */
+  protected onUpdateRequest(msg: Message): void {
+    let context = this._context;
+    if (this.isDisposed || !context.isReady) {
+      return;
+    }
+    let cm = context.contentsModel;
+    let content = context.model.toString();
+    let src = `data:${cm.mimetype};${cm.format},${content}`;
+    this.node.querySelector('img').setAttribute('src', src);
+  }
+
+  /**
+   * Handle `'activate-request'` messages.
+   */
+  protected onActivateRequest(msg: Message): void {
+    this.node.focus();
+  }
+
+  /**
+   * Handle a change to the title.
+   */
+  private _onTitleChanged(): void {
+    this.title.label = this._context.path.split('/').pop();
+  }
+
+  private _context: DocumentRegistry.Context;
+  private _scale = 1;
+}
+
+
+/**
+ * A widget factory for images.
+ */
+export
+class ImageViewerFactory extends ABCWidgetFactory<ImageViewer, DocumentRegistry.IModel> {
+  /**
+   * Create a new widget given a context.
+   */
+  protected createNewWidget(context: DocumentRegistry.IContext<DocumentRegistry.IModel>): ImageViewer {
+    return new ImageViewer(context);
+  }
+}
+
+/**
+ * A namespace for image widget private data.
+ */
+namespace Private {
+  /**
+   * Create the node for the image widget.
+   */
+  export
+  function createNode(): HTMLElement {
+    let node = document.createElement('div');
+    let innerNode = document.createElement('div');
+    let image = document.createElement('img');
+    node.appendChild(innerNode);
+    innerNode.appendChild(image);
+    return node;
+  }
+}

+ 3 - 3
packages/shortcuts-extension/src/index.ts

@@ -118,17 +118,17 @@ const SHORTCUTS = [
     keys: ['Accel Shift H']
   },
   {
-    command: 'imagewidget:zoom-in',
+    command: 'imageviewer:zoom-in',
     selector: '.jp-ImageViewer',
     keys: ['=']
   },
   {
-    command: 'imagewidget:zoom-out',
+    command: 'imageviewer:zoom-out',
     selector: '.jp-ImageViewer',
     keys: ['-']
   },
   {
-    command: 'imagewidget:reset-zoom',
+    command: 'imageviewer:reset-zoom',
     selector: '.jp-ImageViewer',
     keys: ['0']
   },

+ 59 - 0
packages/theme-light/package.json

@@ -0,0 +1,59 @@
+{
+  "name": "@jupyterlab/theme-assets",
+  "version": "0.4.0",
+  "description": "JupyterLab - Default Theme",
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "files": [
+    "lib/*.d.ts",
+    "lib/*.js",
+    "style/*.css",
+    "style/images/*.*",
+    "style/icons/*.*",
+    "style/icons/**/*.*"
+  ],
+  "directories": {
+    "lib": "lib/"
+  },
+  "dependencies": {
+    "@jupyterlab/about-extension": "^0.4.0",
+    "@jupyterlab/application": "^0.4.0",
+    "@jupyterlab/apputils": "^0.4.0",
+    "@jupyterlab/cells": "^0.4.0",
+    "@jupyterlab/codeeditor": "^0.4.0",
+    "@jupyterlab/codemirror": "^0.4.0",
+    "@jupyterlab/completer": "^0.4.0",
+    "@jupyterlab/console": "^0.4.0",
+    "@jupyterlab/csvwidget": "^0.4.0",
+    "@jupyterlab/editorwidget": "^0.4.0",
+    "@jupyterlab/faq-extension": "^0.4.0",
+    "@jupyterlab/filebrowser": "^0.4.0",
+    "@jupyterlab/help-extension": "^0.4.0",
+    "@jupyterlab/imageviewer": "^0.4.0",
+    "@jupyterlab/inspector": "^0.4.0",
+    "@jupyterlab/landing-extension": "^0.4.0",
+    "@jupyterlab/launcher": "^0.4.0",
+    "@jupyterlab/markdownwidget": "^0.4.0",
+    "@jupyterlab/notebook": "^0.4.0",
+    "@jupyterlab/outputarea": "^0.4.0",
+    "@jupyterlab/rendermime": "^0.4.0",
+    "@jupyterlab/running": "^0.4.0",
+    "@jupyterlab/tabmanager-extension": "^0.4.0",
+    "@jupyterlab/terminal": "^0.4.0",
+    "@jupyterlab/tooltip": "^0.4.0"
+  },
+  "devDependencies": {
+    "rimraf": "^2.5.2",
+    "typescript": "^2.2.1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jupyterlab/jupyterlab.git"
+  },
+  "author": "Project Jupyter",
+  "license": "BSD-3-Clause",
+  "bugs": {
+    "url": "https://github.com/jupyterlab/jupyterlab/issues"
+  },
+  "homepage": "https://github.com/jupyterlab/jupyterlab"
+}

+ 1 - 1
test/package.json

@@ -25,7 +25,7 @@
     "@jupyterlab/docregistry": "^0.4.0",
     "@jupyterlab/editorwidget": "^0.4.0",
     "@jupyterlab/filebrowser": "^0.4.0",
-    "@jupyterlab/imagewidget": "^0.4.0",
+    "@jupyterlab/imageviewer": "^0.4.0",
     "@jupyterlab/inspector": "^0.4.0",
     "@jupyterlab/markdownwidget": "^0.4.0",
     "@jupyterlab/notebook": "^0.4.0",

+ 1 - 1
test/src/imagewidget/widget.spec.ts

@@ -25,7 +25,7 @@ import {
 
 import {
   ImageViewer, ImageViewerFactory
-} from '@jupyterlab/imagewidget';
+} from '@jupyterlab/imageviewer';
 
 import {
   createFileContext

+ 1 - 1
test/src/index.ts

@@ -67,7 +67,7 @@ import './editorwidget/widget.spec';
 import './filebrowser/crumbs.spec';
 import './filebrowser/model.spec';
 
-import './imagewidget/widget.spec';
+import './imageviewer/widget.spec';
 
 import './inspector/inspector.spec';
 

+ 1 - 1
tutorial/extensions_dev.md

@@ -29,7 +29,7 @@ exporting a plugin object or array of plugin objects as the default export.
 The default plugins in the JupyterLab application include:
 - [Terminal](https://github.com/jupyterlab/jupyterlab/blob/master/packages/terminal-extension/src/index.ts) - Adds the ability to create command prompt terminals.
 - [Shortcuts](https://github.com/jupyterlab/jupyterlab/blob/master/packages/shortcuts-extension/src/index.ts) - Sets the default set of shortcuts for the application.
-- [Images](https://github.com/jupyterlab/jupyterlab/blob/master/packages/imagewidget-extension/src/index.ts) - Adds a widget factory for displaying image files.
+- [Images](https://github.com/jupyterlab/jupyterlab/blob/master/packages/imageviewer-extension/src/index.ts) - Adds a widget factory for displaying image files.
 - [Help](https://github.com/jupyterlab/jupyterlab/blob/master/packages/help-extension/src/index.ts) - Adds a side bar widget for displaying external documentation.
 - [File Browser](https://github.com/jupyterlab/jupyterlab/blob/master/packages/filebrowser-extension/src/index.ts) - Creates the file browser and the document manager and the file browser to the side bar.
 - [Editor](https://github.com/jupyterlab/jupyterlab/blob/master/packages/editorwidget-extension/src/index.ts) - Add a widget factory for displaying editable source files.