#!/usr/bin/env ruby
require 'gtk2'
require 'find'
require 'fileutils'
# this is Marvin the file/project manager for scite, using ruby/gtk2.
# enable 'check.if.already.open=1' in scite's Global Config file
# other tabbed text editors must support multiple opens in a
# current session otherwise there will be a new window for each file.
# check http://forum.ruby-portal.de/viewtopic.php?p=31271&sid=7ad2ffde86d46016419127684f662410
# for the original treeview implementation of treestore loading.
# TODO: review treestore/treeview handling code. It may be best served if there
# is a modified/inherited TreeView class handling all the mess
# FIXED: mkdir and background simbol (&) at each editor call.
#
class TextInputDialog < Gtk::Dialog
def initialize (title, path)
super()
set_modal(true)
set_default_size(200,100)
set_title(title)
entryText = Gtk::Entry.new
vbox.add(entryText)
btOk = Gtk::Button.new('Ok')
btCancel = Gtk::Button.new('Cancel')
action_area.add(btOk)
action_area.add(btCancel)
btOk.signal_connect('clicked') do
@filename=entryText.text
response(Gtk::Dialog::RESPONSE_ACCEPT)
end
btCancel.signal_connect('clicked') do
response(Gtk::Dialog::RESPONSE_CANCEL)
end
show_all
end
def filename
@filename
end
end
class Marvin < Gtk::Window
def buildTreeModel(model, cwd)
this = []
that = [nil]
Find.find(cwd) do |path|
path = path.sub(/#{cwd}/, '');
counter = 0
path.scan(/([^\/]+)\/?/).flatten.each do |element|
counter += 1
if this[counter] != element then
this[counter] = element
that[counter] = model.append(that[counter - 1]).set_value(0, this[counter])
end
end
end
end
def updateTreeModel (model)
model.clear
buildTreeModel(model, @tcwd)
end
def showAboutDialog
props = {
:name => 'marvin.rb',
:copyright => %{\
(C) 2007 gm
},
:comments => %{\
A simple file manager for scite written on rails/gtk2},
:website => 'https://zenmachine.wordpress.com/',
}
Gtk::AboutDialog.show(nil, props)
end
def createMenuBar
topmen = Gtk::MenuItem.new( "Main" )
menu = Gtk::Menu.new
item = Gtk::MenuItem.new( "About" )
item.signal_connect("activate") { showAboutDialog }
menu.append( item )
item = Gtk::SeparatorMenuItem.new
menu.append(item)
item = Gtk::MenuItem.new( "Quit" )
item.signal_connect("activate") { Gtk.main_quit }
menu.append( item )
topmen.set_submenu( menu )
menubar = Gtk::MenuBar.new
menubar.append( topmen )
return menubar
end
def itemContextMenu(event, path, model)
menu = Gtk::Menu.new
item = Gtk::MenuItem.new("New File")
item.signal_connect("activate") {
txtdlg = TextInputDialog.new("Create new file", path)
if txtdlg.run == Gtk::Dialog::RESPONSE_ACCEPT
newFile=path+"/"+txtdlg.filename
end
txtdlg.destroy
if (File.exists?(newFile))
errdlg=Gtk::MessageDialog.new(nil,
Gtk::MessageDialog::DESTROY_WITH_PARENT,
Gtk::MessageDialog::INFO, Gtk::MessageDialog::BUTTONS_CLOSE,
"File already exists")
errdlg.run
errdlg.destroy
else
puts "Creating: "+newFile
FileUtils.touch(newFile)
system @textEditor+newFile+"&"
# rebuild tree model
updateTreeModel(model)
end
}
menu.append(item)
item = Gtk::MenuItem.new("New Folder")
item.signal_connect("activate") {
if (not File.directory?(path))
path=File.dirname(path)
end
txtdlg = TextInputDialog.new("Create new folder", path)
if txtdlg.run == Gtk::Dialog::RESPONSE_ACCEPT
newFolder=path+"/"+txtdlg.filename
end
txtdlg.destroy
if (File.exists?(newFolder))
errdlg=Gtk::MessageDialog.new(nil,
Gtk::MessageDialog::DESTROY_WITH_PARENT,
Gtk::MessageDialog::INFO, Gtk::MessageDialog::BUTTONS_CLOSE,
"Folder already exists")
errdlg.run
errdlg.destroy
else
puts "Creating: "+newFolder
Dir.mkdir(newFolder)
# rebuild tree model
updateTreeModel(model)
end
}
menu.append(item)
item = Gtk::MenuItem.new("Delete")
item.signal_connect("activate") {
if (not File.exists?(path))
# msgdialog ok/cancel
errdlg=Gtk::MessageDialog.new(nil,
Gtk::MessageDialog::DESTROY_WITH_PARENT,
Gtk::MessageDialog::INFO, Gtk::MessageDialog::BUTTONS_CLOSE,
"Folder not found")
errdlg.run
errdlg.destroy
else
puts "Deleting: "+path
FileUtils.rm_r(path, :secure=>true)
# rebuild tree model
updateTreeModel(model)
end
}
menu.append(item)
menu.show_all()
menu.popup(nil, nil, event.button, event.time)
end
def createTree(cwd, model)
expandedRows = Array.new
tree = Gtk::TreeView.new model
tree.signal_connect("row-activated") { |view, path, column|
if iter = view.model.get_iter(path)
path = [iter[0]]
while iter.parent != nil
iter = iter.parent
path << iter[0]
end
path = cwd + "/" + path.reverse.join("/")
if (not FileTest.directory? path)
system @textEditor+" "+path+"&"
end
end
}
tree.signal_connect("button_press_event") do |widget, event|
if event.kind_of? Gdk::EventButton and event.button==3
widget.selection.selected_each { |tModel, path, iter|
if iter = tModel.get_iter(path)
path = [iter[0]]
while iter.parent != nil
iter = iter.parent
path << iter[0]
end
# save expand status
expandedRows.clear
tree.map_expanded_rows do |tree,treepath|
expandedRows << treepath
end
path = cwd + "/" + path.reverse.join("/")
itemContextMenu(event, path, model)
end
}
end
end
model.signal_connect("row-changed") {
#restore any stored expand status
expandedRows.each do |tp|
tree.expand_row(tp, false)
end
}
render = Gtk::CellRendererText.new()
c1 = Gtk::TreeViewColumn.new(cwd, render, {:text => 0})
tree.append_column(c1)
buildTreeModel(model, cwd)
return tree
end
def selectWorkingDir
dialog = Gtk::FileChooserDialog.new("Select Project Directory",
nil,
Gtk::FileChooser::ACTION_SELECT_FOLDER,
nil,
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
peta=dialog.current_folder #+"/"
end
dialog.destroy
return peta
end
def initialize
super()
# change your text editor here (but remember to check if it can open new files in the same window/new tab)
@textEditor="scite"
@tcwd=selectWorkingDir()
self.set_size_request(240, 600)
self.signal_connect("delete_event") { Gtk.main_quit }
self.set_title("Marvin")
vbox2 = Gtk::VBox.new(false, 0)
menubar = createMenuBar()
vbox2.pack_start(menubar, false, false, 0)
scroller = Gtk::ScrolledWindow.new
scroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
vbox2.pack_start(scroller, true, true, 0)
model = Gtk::TreeStore.new(String)
tree = createTree(@tcwd, model)
scroller.add(tree)
self.add(vbox2)
self.show_all()
end
end
Gtk.init
Marvin.new
Gtk.main
Like this:
Like Loading...