Skip to content
Snippets Groups Projects
gembrowser.rb 7.28 KiB
Newer Older
  • Learn to ignore specific revisions
  • require 'fox16'
    
    include Fox
    
    class GemBrowser
    
      #
      # A reference to the currently selected Gem specification, or +nil+
      # if none is selected.
      #
      attr_accessor :currentSpec
    
      def initialize
        @currentSpec = nil
      end
    
      #
      # Install the Gem described by the named spec file, and return the
      # Specification for this Gem.
      #
      def install(filename)
        Gem::Installer.new(filename).install
        spec = nil
        cache.each do |n, s|
          spec = s if (File.basename(filename, ".gem") == s.full_name)
        end
        spec
      end
    
      #
      # Uninstall the Gem described by this specification.
      #
      def uninstall(spec)
        Gem::Uninstaller.new(spec.name).uninstall
      end
    
      # Return an array of the installed specifications.
      def cache
    #   Gem.cache
    
    Lars Kanis's avatar
    Lars Kanis committed
        Gem::SourceIndex.from_installed_gems
    
      end
    end
    
    class GemInfoPanel < FXVerticalFrame
    
      attr_reader :browser
    
      def initialize(p, b, opts)
        # Initialize base class
        super(p, opts)
    
        @browser = b
    
        self.backColor = FXRGB(255, 255, 255)
    
    
    Lars Kanis's avatar
    Lars Kanis committed
        File.open(File.expand_path("../icons/gem_big.png", __FILE__), "rb") do |f|
    
          @bigIcon = FXPNGIcon.new(getApp(), f.read)
        end
    
        nameLabel = FXLabel.new(self, "", @bigIcon, JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_FILL_X)
        nameLabel.backColor = FXRGB(255, 255, 255)
        nameLabel.connect(SEL_UPDATE) { |nameLabel, sel, ptr|
          if currentSpec
    	nameLabel.text = specDescription(currentSpec)
    	nameLabel.show
          else
    	nameLabel.text = ""
    	nameLabel.hide
          end
        }
    
        summaryText = FXText.new(self, nil, 0, TEXT_READONLY|TEXT_WORDWRAP|LAYOUT_FILL_X|LAYOUT_FILL_Y)
        summaryText.backColor = FXRGB(255, 255, 255)
        summaryText.connect(SEL_UPDATE) { |summaryText, sel, ptr|
          theText = currentSpec ? currentSpec.summary : nil
          summaryText.text = theText unless (summaryText.text == theText)
        }
      end
    
      #
      # Return a reference to the currently selected Gem specification,
      # or +nil+ if none is selected.
      #
      def currentSpec
        browser.currentSpec
      end
    
      # Return a multiline string (suitable for use with an FXLabel) describing this spec.
      def specDescription(spec)
        [spec.name, "version #{spec.version}", spec.author, spec.email, spec.homepage].join("\n")
      end
    
      def create
        super
        @bigIcon.create
      end
    end
    
    class GemsPanel < FXVerticalFrame
    
      attr_reader :browser
    
      def initialize(p, br, opts)
        # Initialize base class
        super(p, opts)
    
        # Save a reference to the browser
        @browser = br
    
    
    Lars Kanis's avatar
    Lars Kanis committed
        File.open(File.expand_path("../icons/gem_big.png", __FILE__), "rb") do |f|
    
          @bigIcon = FXPNGIcon.new(getApp(), f.read)
        end
    
    Lars Kanis's avatar
    Lars Kanis committed
        File.open(File.expand_path("../icons/gem_small.png", __FILE__), "rb") do |f|
    
          @smallIcon = FXPNGIcon.new(getApp(), f.read)
        end
    
        @iconList = FXIconList.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|ICONLIST_MINI_ICONS|ICONLIST_BROWSESELECT)
        @iconList.connect(SEL_SELECTED) { |sender, sel, ptr|
          browser.currentSpec = itemSpec(ptr)
        }
    
        # Fill the list with installed specifications.
        browser.cache.each { |name, spec| appendItem(spec) }
        if numItems > 0
          selectItem(0)
          browser.currentSpec = itemSpec(0)
        end
      end
    
      def appendItem(spec)
        @iconList.appendItem(spec.name, @bigIcon, @smallIcon, spec)
        if numItems == 1
          selectItem(0)
          browser.currentSpec = itemSpec(0)
        end
      end
    
      def currentItem
        @iconList.currentItem
      end
    
      #
      # Return the specification associated with the item at _index_, or
      # +nil+ if no such item.
      #
      def itemSpec(index)
        (index >= 0) ? getItem(index).data : nil
      end
    
      def currentItemSpec
        itemSpec(currentItem)
      end
    
      def getItem(*args)
        @iconList.getItem(*args)
      end
    
      def selectItem(index)
        @iconList.selectItem(index, true)
      end
    
      def numItems
        @iconList.numItems
      end
    
      def create
        super
        @bigIcon.create
        @smallIcon.create
        self.width = @iconList.font.getTextWidth("MMMMMMMMMMMMM")
      end
    end
    
    class GemBrowserWindow < FXMainWindow
    
      attr_reader :browser
    
      def initialize(anApp)
        # Initialize base class first
        super(anApp, "Gem Browser", nil, nil, DECOR_ALL)
    
        # Menu bar
    
        menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
    
    
        # File menu
        filemenu = FXMenuPane.new(self)
        FXMenuTitle.new(menubar, "&File", nil, filemenu)
    
        installCmd = FXMenuCommand.new(filemenu, "Install a Gem...")
        installCmd.connect(SEL_COMMAND) { install }
    
        uninstallCmd = FXMenuCommand.new(filemenu, "Uninstall this Gem")
        uninstallCmd.connect(SEL_COMMAND) { uninstall }
        uninstallCmd.connect(SEL_UPDATE) do |sender, sel, ptr|
          spec = browser.currentSpec
          if spec
            sender.text = "Uninstall #{spec.name}"
            sender.enable
          else
            sender.text  = "Uninstall this Gem"
            sender.disable
          end
        end
    
        FXMenuCommand.new(filemenu, "&Quit\tCtl-Q").connect(SEL_COMMAND) { quit }
    
        # Main window interior
        contents = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y)
    
        @browser = GemBrowser.new
    
        # Horizontal splitter with info pane on the left, icon list on the right
        @splitter = FXSplitter.new(contents, LAYOUT_FILL_X|LAYOUT_FILL_Y|SPLITTER_HORIZONTAL|SPLITTER_REVERSED) do |splitter|
          infoPanel = GemInfoPanel.new(splitter, @browser, LAYOUT_FILL_X|LAYOUT_FILL_X|FRAME_SUNKEN|FRAME_THICK)
          @gemsPanel = GemsPanel.new(splitter, @browser, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK)
        end
    
        # Catch these too
        self.connect(SEL_CLOSE) { quit }
        anApp.addSignal("SIGINT") { quit }
      end
    
      def install
        FXFileDialog.new(self, "Install Gem") { |dlg|
          dlg.directory = @directory unless @directory.empty?
          dlg.patternList = ["Gem Files (*.gem)", "All Files (*)"]
          if dlg.execute != 0
            @directory = dlg.directory
    
              spec = browser.install(dlg.filename)
    	  @gemsPanel.appendItem(spec)
    	rescue => ex
    
    	  FXMessageBox.error(self, MBOX_OK, "Installation Failed", ex.to_s)
    
    	end
          end
        }
      end
    
      def uninstall
        begin
          browser.uninstall(browser.currentSpec)
        rescue => ex
          FXMessageBox.error(self, MBOX_OK, "Uninstall Failed", ex.to_s)
        end
      end
    
      def quit
        getApp().reg().writeIntEntry("SETTINGS", "x", x)
        getApp().reg().writeIntEntry("SETTINGS", "y", y)
        getApp().reg().writeIntEntry("SETTINGS", "width", width)
        getApp().reg().writeIntEntry("SETTINGS", "height", height)
        getApp().reg().writeIntEntry("SETTINGS", "listWidth", @splitter.first.next.width)
        getApp().reg().writeStringEntry("SETTINGS", "directory", @directory) if @directory
        getApp().exit(0)
      end
    
      def create
        # Do base class create
        super
    
        # Get size, etc. from registry
        xx = getApp().reg().readIntEntry("SETTINGS", "x", 0)
        yy = getApp().reg().readIntEntry("SETTINGS", "y", 0)
        ww = getApp().reg().readIntEntry("SETTINGS", "width", 450)
        hh = getApp().reg().readIntEntry("SETTINGS", "height", 300)
        position(xx, yy, ww, hh)
    
        # Splitter child sizes
        rightPaneSize = getApp().reg().readIntEntry("SETTINGS", "listWidth", -1)
        if rightPaneSize >= 0
          @splitter.first.next.width = rightPaneSize
        end
    
        # Last directory for Gem files
        @directory = getApp().reg().readStringEntry("SETTINGS", "directory", "")
    
        # Show it
        show
      end
    end
    
    if __FILE__ == $0
      FXApp.new("GemBrowser", "FXRuby") do |theApp|
        GemBrowserWindow.new(theApp)
        theApp.create
        theApp.run
      end
    end