dragonfly-grammars/holding/_explorer_tools.py

247 lines
7.8 KiB
Python

#
# This file is a command-module for Dragonfly.
# (c) Copyright 2008 by Christo Butcher
# Licensed under the LGPL, see <http://www.gnu.org/licenses/>
#
"""
Command-module to control **Windows Explorer**
============================================================================
This module defines various voice-commands for use with Windows Explorer.
.. note::
This module is still under development.
Installation
----------------------------------------------------------------------------
If you are using DNS and Natlink, simply place this file in you Natlink
macros directory. It will then be automatically loaded by Natlink when
you next toggle your microphone or restart Natlink.
"""
try:
import pkg_resources
pkg_resources.require("dragonfly >= 0.6.5beta1.dev-r76")
except ImportError:
pass
import os.path
import string
import subprocess
import time
from urllib import unquote
from dragonfly import (ConnectionGrammar, AppContext, CompoundRule,
Choice, Window, Config, Section, Item)
#---------------------------------------------------------------------------
class SingleFile(object):
def __init__(self, spec, command_line):
self.spec = spec
self.command_line = command_line
def execute(self, paths, directory):
for path in paths:
self.execute_single(path, directory)
def execute_single(self, path, directory):
data = {"path": path, "dir": directory}
arguments = [s % data for s in self.command_line]
print "Arguments: %r" % arguments
process = subprocess.Popen(arguments, stdout=subprocess.PIPE)
out, err = process.communicate()
print "Output:"; print out and out.strip()
print "Error:"; print err and err.strip()
class MultiFile(object):
def __init__(self, spec, command_line_pre, command_line_post):
self.spec = spec
self.command_line_pre = command_line_pre
self.command_line_post = command_line_post
def execute(self, paths, directory):
data = {"dir": directory}
arguments_pre = [s % data for s in self.command_line_pre]
arguments_post = [s % data for s in self.command_line_post]
arguments = arguments_pre + paths
if arguments_post:
arguments += arguments_post
print "Arguments: %r" % arguments
process = subprocess.Popen(arguments, stdout=subprocess.PIPE)
out, err = process.communicate()
print "Output:"; print out and out.strip()
print "Error:"; print err and err.strip()
class CreateArchiveHere(object):
def __init__(self, spec, extension):
self.spec = spec
self.extension = extension
def execute(self, paths, directory):
archive_path = os.path.splitext(os.path.basename(paths[0]))[0]
archive_path = os.path.join(directory, archive_path)
archive_path += time.strftime("-%y%m%d")
def filenames(basename, extension):
# yield basename + extension
for letter in string.lowercase:
yield basename + letter + extension
available = False
for archive_path in filenames(archive_path, self.extension):
if not os.path.exists(archive_path):
available = True
break
if not available:
print "Warning: could not create archive."
return
arguments = [r"C:\Program Files\7-Zip\7z.exe", "a"]
arguments.append("-o" + directory)
arguments.append(archive_path)
# arguments.append(os.path.splitext(archive_path)[0])
arguments.extend(paths)
print "Arguments: %r" % arguments
process = subprocess.Popen(arguments, stdout=subprocess.PIPE)
out, err = process.communicate()
print "Output:"; print out and out.strip()
print "Error:"; print err and err.strip()
class RenameFile(object):
python_path = r"C:\Python25\python.exe"
rename_dialog_path = os.path.join(os.path.dirname(__file__),
"dialog_rename.py")
def __init__(self, spec):
self.spec = spec
def execute(self, paths, directory):
if len(paths) == 0:
print "Rename file error: nothing selected."
return
path = paths[0]
arguments = [self.python_path, self.rename_dialog_path, path]
subprocess.Popen(arguments)
#---------------------------------------------------------------------------
commands = [
SingleFile("open with ultra [edit]",
[r"C:\Program Files\IDM Computer Solutions\UltraEdit\Uedit32.exe", "%(path)s"]),
MultiFile("scan for (virus | viruses) | virus scan",
[r"C:\Program Files\F-Secure\Anti-Virus\fsav.exe"], ["/list"]),
SingleFile("extract archive here",
[r"C:\Program Files\7-Zip\7z.exe", "x", "-o%(dir)s", "%(path)s"]),
CreateArchiveHere("create zip archive here", ".zip"),
CreateArchiveHere("create [7] archive here", ".7z"),
RenameFile("rename file dialog"),
]
#---------------------------------------------------------------------------
# Utility generator function for iterating over COM collections.
def collection_iter(collection):
for index in xrange(collection.Count):
yield collection.Item(index)
#---------------------------------------------------------------------------
# This module's main grammar.
class ControlGrammar(ConnectionGrammar):
def __init__(self):
ConnectionGrammar.__init__(
self,
name="Explorer control",
context=AppContext(executable="explorer"),
app_name="Shell.Application"
)
def get_active_explorer(self):
handle = Window.get_foreground().handle
for window in collection_iter(self.application.Windows()):
if window.HWND == handle:
return window
self._log.warning("%s: no active explorer." % self)
return None
def get_selected_paths(self):
window = self.get_active_explorer()
items = window.Document.SelectedItems()
paths = []
for item in collection_iter(items):
paths.append(item.Path)
print "Selected paths: %r" % paths
return paths
def get_selected_filenames(self):
paths = self.get_selected_paths()
return [os.path.basename(p) for p in paths]
def get_current_directory(self):
window = self.get_active_explorer()
path = window.LocationURL[8:]
if path.startswith("file:///"):
path = path[8:]
return unquote(path)
grammar = ControlGrammar()
#---------------------------------------------------------------------------
class ListSelectionRule(CompoundRule):
spec = "list current selection"
def _process_recognition(self, node, extras):
print "Current selection:"
for filename in self.grammar.get_selected_filenames():
print " - %r" % filename
grammar.add_rule(ListSelectionRule())
#---------------------------------------------------------------------------
class CommandRule(CompoundRule):
spec = "[command] <command>"
extras = [Choice("command", dict((c.spec, c) for c in commands))]
def _process_recognition(self, node, extras):
command = extras["command"]
paths = self.grammar.get_selected_paths()
directory = self.grammar.get_current_directory()
print "Selected paths: %r" % paths
command.execute(paths, directory)
grammar.add_rule(CommandRule())
#---------------------------------------------------------------------------
# Load the grammar instance and define how to unload it.
grammar.load()
# Unload function which will be called by natlink at unload time.
def unload():
global grammar
if grammar: grammar.unload()
grammar = None