Fan

 

class

flux::ErrResource

sys::Obj
  flux::Resource
    flux::ErrResource
//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   21 Jul 08  Brian Frank  Creation
//

using gfx
using fwt

**
** Resource represents the objects a user navigates, views, and
** edits in a flux application.  Resources are mapped to objects
** via the '@fluxResource' facet - if keyed by this facet, then
** subclass must define a 'make(Uri, Obj)' constructor.
**
** See `docLib::Flux` for details.
**
abstract class Resource
{

  **
  ** Get the root resources.
  **
  static Resource[] roots()
  {
    File.osRoots.map |File f->Resource| { FileResource.makeFile(f) }
  }

  **
  ** Resolve a uri into a resource:
  **   1.  Resolve uri to obj via `sys::Uri.get`
  **   2.  If obj is Resource, return it
  **   3.  Resolve to obj type to resource type via '@fluxResource' facet
  **
  ** Throw UnresolvedErr if the uri can't be resolved, and UnsupportedErr
  ** if resource can't be mapped to a resource.
  **
  static Resource resolve(Uri uri)
  {
    // 1. resolve uri
    obj := uri.get

    // 2. if already resource return it
    if (obj is Resource) return obj

    // 3. map via fluxResource facet
    rtype := Type.findByFacet(@fluxResource, obj.type, true).first
    if (rtype == null) throw UnsupportedErr("No resource mapping for $obj.type")
    return rtype.make([uri, obj])
  }

  **
  ** Get the absolute Uri of this resource.
  **
  abstract Uri uri()

  **
  ** Get the display name of the resource.
  **
  abstract Str name()

  **
  ** Get a 16x16 icon for the resource.
  **
  virtual Image icon() { return Flux.icon(`/x16/file.png`) }

  **
  ** Return if this resource has or might have children.  This
  ** is an optimization to display the expansion control in a tree
  ** without loading all the children.  The default calls 'children'.
  **
  virtual Bool hasChildren()
  {
    c := children
    return c != null ? !c.isEmpty : false
  }

  **
  ** Get the navigation children of the resource.  Return an
  ** empty list or null to indicate no children.  Default
  ** returns null.
  **
  virtual Resource[]? children() { return null}

  **
  ** Get the list of available `View` types for the resource.
  ** The first view should be the default view.  The default
  ** implementation searches the type database for '@fluxView'
  ** bindings to this resource type.
  **
  virtual Type[] views()
  {
    acc := Type.findByFacet(@fluxView, type, true)
    acc = acc.exclude |Type t->Bool| { return t.isAbstract }
    return acc
  }

  **
  ** Make a popup menu for this resource or return null.
  ** The default popup menu returns the `viewsMenu`.
  **
  virtual Menu? popup(Frame? frame, Event? event)
  {
    return Menu { add(viewsMenu(frame, event)) }
  }

  **
  ** Return a menu to hyperlink to the views supported
  ** by this resource.
  **
  virtual Menu? viewsMenu(Frame? frame, Event? event)
  {
    menu := Menu { text = this.type.loc("views.name") }
    views.each |Type v, Int i|
    {
      viewUri := i == 0 ? uri : uri.plusQuery(["view":v.qname])
      c := Command(v.name, null, &frame.load(viewUri, LoadMode(event)))
      menu.add(MenuItem { command = c })
    }
    return menu
  }

  **
  ** Return `uri`.
  **
  override Str toStr() { return uri.toStr }
}

**************************************************************************
** ErrResource
**************************************************************************

**
** ErrResource models a resource that cannot be resolved.
**
class ErrResource : Resource
{

  new make(Uri uri) { this.uri = uri }

  override Uri uri

  override Str name() { n := uri.name; return n.isEmpty ? uri.toStr : n }

  override Image icon() { return Flux.icon(`/x16/err.png`) }

  override Type[] views() { return Type[,] }

}