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 Gem::Cache.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) File.open(File.join("icons", "gem_big.png"), "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 File.open(File.join("icons", "gem_big.png"), "rb") do |f| @bigIcon = FXPNGIcon.new(getApp(), f.read) end File.open(File.join("icons", "gem_small.png"), "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 begin 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