#!/usr/local/bin/ruby require 'rubygems' require 'fox14' require 'find' require "yaml" include Fox class ProjWindow < FXMainWindow # ignore files matching these patterns by default $def_exclude= [ /\.obj$/i, /\.o$/i, /\.dll$/i, /\.so$/i, /\.bak$/i, /\.asv$/i, /\.class/ ] $def_exclude_dirs= [ /^(CVS|\.svn)$/ ] def excluded(f, exc) exc.each do |r| return true if r.match(f) end $def_exclude.each do |r| return true if r.match(f) end return nil end def excluded_dirs(d, exc) exc.each do |r| return true if r.match(d) end $def_exclude_dirs.each do |r| return true if r.match(d) end return nil end # load project specific excludes def get_local_exclude(cd) ex= {} exf= File.join(cd, ".proj_exclude.yaml") if File.exists?(exf) ex= YAML.load_file(exf) end exr= {} exr[:files]= [] exr[:dirs]= [] unless ex[:files].nil? ex[:files].each do |r| exr[:files] << Regexp.new(r) end end unless ex[:dirs].nil? ex[:dirs].each do |r| exr[:dirs] << Regexp.new(r) end end puts "Excludes: " p exr return exr end def create super # make sure the icons are created on the server-side @folder_open.create @folder_closed.create show(PLACEMENT_SCREEN) end def initialize(app) @running= false @tabs= [] # Invoke base class initializer first super(app, "Project Browser", nil, nil, DECOR_ALL, 0, 0, 350, 1024) # Menu bar menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X) setupMenu(menubar) # Construct a horizontal frame to hold the main window's contents @contents = FXVerticalFrame.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0) @tab_frame= FXTabBook.new(@contents, nil, 0, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_RIGHT) @tab_frame.connect(SEL_COMMAND) do |sender, sel, ptr| #puts "selected tab: #{ptr}" @curtree, @curpath= @tabs[ptr] end button_frame= FXHorizontalFrame.new(@contents, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|FRAME_THICK|FRAME_RAISED) FXButton.new(button_frame, "&Refresh", nil, nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT, 0, 0, 0, 0, 10, 10, 5, 5).connect(SEL_COMMAND) do show_project_list(@curpath, true) end # Exit button FXButton.new(button_frame, "&Exit", nil, app, FXApp::ID_QUIT, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_RIGHT, 0, 0, 0, 0, 10, 10, 5, 5) # Construct some icons we'll use @folder_open = makeIcon("minifolderopen.png") @folder_closed = makeIcon("minifolder.png") @icons= { # Map filetype to icon :ruby_file => makeIcon("ruby_file.png"), :normal => makeIcon("normal_file.png") } @ntabs= 0 ARGV.each do |path| if File.directory?(path) @curpath= path show_project_list(@curpath) else puts "#{path} is not a directory" end end @running= true end # Convenience function to load & construct an icon def makeIcon(filename) begin filename= File.join( File.dirname(__FILE__), 'icons', filename) icon = nil File.open(filename, "rb") { |f| icon = FXPNGIcon.new(getApp(), f.read) } icon rescue raise RuntimeError, "Couldn't load icon: #{filename}" end end def show_project_list(projdir, refresh=false) unless refresh tab= FXTabItem.new(@tab_frame, "&#{File.basename(File.expand_path(projdir))}", nil) frame= FXHorizontalFrame.new(@tab_frame, FRAME_THICK|FRAME_RAISED) project_tree = FXTreeList.new(frame, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|TREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|TREELIST_ROOT_BOXES ) if @running tab.create frame.create project_tree.create @tab_frame.setCurrent(@ntabs) end project_tree.connect(SEL_COMMAND) do |sender, sel, ptr| r= ptr.data #puts "clicked on path item: #{r.to_s}" system("epsilon -add #{r.to_s} > /dev/null") end @curtree= project_tree @tabs[@ntabs]= [project_tree, projdir] @ntabs += 1 else project_tree= @curtree end if show_proj_tree(project_tree, projdir) > 0 project_tree.expandTree(project_tree.firstItem) project_tree.sortItems else puts "No files found" exit(1) end end def show_proj_tree(treewidget, projdir) treewidget.clearItems() dir= {} cnt= 0 local_exclude= get_local_exclude(projdir) Find.find(projdir) do |f| dirname = File.dirname(f) basename = File.basename(f) #puts "#{dirname}: #{basename}" Find.prune if excluded_dirs(basename, local_exclude[:dirs]) if File.directory? f cnt+=1 dir[f]= treewidget.appendItem(dir[dirname], basename, @folder_open, @folder_closed, nil) if basename =~ /app|plugins/ treewidget.expandTree(dir[f]) end else next if excluded(f, local_exclude[:files]) if basename =~ /\.rb$/ ico= @icons[:ruby_file] else ico= @icons[:normal] end treewidget.appendItem(dir[dirname], basename, ico, ico, f) cnt+=1 end end cnt end def setupMenu(menubar) # File menu filemenu = FXMenuPane.new(self) FXMenuCommand.new(filemenu, "New\tCtl-N", nil).connect(SEL_COMMAND) { dirDiag = FXDirDialog.new(self, "New Project Directory") dirDiag.setDirectory(@curpath) dirDiag.forceRefresh() if (dirDiag.execute != 0) @curpath = dirDiag.getDirectory show_project_list(@curpath) end } FXMenuCommand.new(filemenu, "Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT) FXMenuTitle.new(menubar, "&File", nil, filemenu) end end # Construct a FOX application object $application = FXApp.new("project_browser", "project_browser") # Construct the main window ProjWindow.new($application) # Create all the windows $application.create # Run the application $application.run