Date: Mon, 02 Nov 1998 22:59:24 -0700
From: Andrew Dalke <dalke@bioreason.com>
Subject: ANN: CrossCopy
Below is my first real Python program (from about 6 months ago).
It mostly solved a frustration that I no longer have.
The problem:
Our bug database was on an NT box but our code ran on SGIs.
If there was a bug in the code and we wanted to copy&paste
text into the database entry form we would have to save to a file
on the SGI, (re)load the file on the NT then copy&paste
*that* text into the form.
Needless to say, this got boring fast.
One solution:
At this time I was reading the Python documentation and
itching to write some real code. What I wrote was a simple
Tk GUI that ran an HTTP server. The GUI contained a list
of servers and when a server was selected would connect
to it an display the text, which could be cut&pasted (saving
the manual "write to a temporary file" step).
The HTTP server would listen for requests and serve the
text in its text box.
Another solution:
Get another job where everything can be done on the same
machine (the joys of a web interface to the bug database :)
An implementation to the first solution is below. After some
thought I decided to name is "CrossCopy." AltaVista comes up
with no matching names, which I found surprising.
There's all sorts of things that could be done:
read configuration from a file
allow users to edit the configuration
add a "Clear" button
pull the text directly from the cut buffer or moral equivalent
recognize that you cannot connect to yourself (or use multiple
threads) -- at present this causes the system to freeze.
Since I no longer have the problem, I spent no more time in
development. However, I figured others here might find such
a program useful and even be willing to work on it (that's what
ESR says, right? :) so, presented for your approval, the
source. The copyright is the same as Python's, but with
explicit perrmision to distribute modified versions.
Andrew Dalke
dalke@bioreason.com
#!/usr/local/bin/python
# Copyright 1998 by Andrew Dalke -- All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software
# (including modifications) and its documentation for any purpose and
# without fee is hereby granted, provided that the above copyright
# notice appear in all copies and that both that copyright notice and
# this permission notice appear in supporting documentation.
#
# ANDREW DALKE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
# NO EVENT SHALL ANDREW DALKE OR BIOREASIN, INC. BE LIABLE FOR ANY
# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
# RESULTING FROM LOSS OF USE, DATA OR PROFITS,WHETHER IN AN ACTION OF
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import BaseHTTPServer, urllib
import sys, os, select, getopt, socket
from Tkinter import *
class CrossCopyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
self.end_headers()
self.wfile.write(server_text())
class RemoteInfo:
def __init__(self, url, title = '', username = '',
password = ''):
if title == '': # human text (defaults to url)
self.title = url
else:
self.title = title
self.url = url # where is the server?
self.username = username # not used
self.password = password # not used
def goto(self):
get_text(self.url)
###################### configuration information ################
# You'll want to modify this for your system.
# Should read from file ...
remote = []
remote.append(RemoteInfo('http://bioreason3:8000/'))
remote.append(RemoteInfo('http://bioreason8:8000/'))
remote.append(RemoteInfo('http://bioreason9:8000/'))
#### Get the text to pass back to the client (from the server)
def server_text():
global ccserver
global ccclient
global root
if ccclient is not None:
return ccclient.text.get("0.0", "end")
return root.selection_get()
####### Client GUI Code
class CrossCopyClient:
def __init__(self, root):
# make a menu bar
self.mBar = Frame(root, relief=RAISED, borderwidth=2)
self.mBar.pack(fill=X)
self.Command_button = self.makeCommandMenu(self.mBar)
self.Edit_button = self.makeEditMenu(self.mBar) ## no remote
self.mBar.tk_menuBar(self.Command_button)
self.text = Text(root)
self.text.pack()
# menu bars
def makeCommandMenu(self, mBar):
Command_button = Menubutton(mBar, text='File',
underline=0)
Command_button.pack(side=LEFT, padx="2m")
Command_button.menu = Menu(Command_button)
Command_button.menu.add_command(label='Quit', underline=0,
command=quit)
# set up a pointer from the file menubutton back to the file menu
Command_button['menu'] = Command_button.menu
return Command_button
def makeEditMenu(self, mBar):
global remote
Edit_button = Menubutton(mBar, text='Edit',
underline = 0)
Edit_button.pack(side=LEFT, padx="2m")
Edit_button.menu = Menu(Edit_button)
for r in remote:
Edit_button.menu.add_command(label= r.title, command=r.goto)
Edit_button['menu'] = Edit_button.menu
return Edit_button
###### Server code
class CrossCopyServer:
def __init__(self, port):
# Start the web server
self.server_class = BaseHTTPServer.HTTPServer
self.handler_class = CrossCopyHandler
self.server_address = ('', port)
self.httpd = self.server_class(self.server_address, self.handler_class)
def fileno(self):
return self.httpd.fileno()
def handle_request(self):
return self.httpd.handle_request()
def get_text(url):
a = urllib.urlopen(url)
ccclient.text.delete('0.0', 'end')
ccclient.text.insert('end', a.read())
def quit():
root.quit()
def check_ccserver():
global ccserver
global root
if select.select([ccserver], [], [], 0) == ([ccserver], [], []):
ccserver.handle_request()
root.after(200, check_ccserver)
if __name__ == '__main__':
server = 1
client = 1
port = 8000
initfile = '/u/dalke/.crosscopyrc' # not the we use it ... yet
args = sys.argv[:]
try:
opts, rest = getopt.getopt(sys.argv[1:], '',
['client=', 'server=', 'port=', 'file='])
if len(rest) > 2: raise getopt.error, 'too many arguments'
for option, optarg in opts:
if option == '--server':
server = int(optarg)
elif option == '--client':
client = int(optarg)
elif option == '--port':
port = int(optarg)
elif option == '--file':
initfile = optarg
except getopt.error, msg:
print msg
print 'Usage: ',
print sys.argv[0],
print ' [--server [0|1] ] [--client [0|1]] [--port <number>]'
# should read configuration file here
root = Tk()
# unix specific so ignore for now (should check environ)
# hostname = os.popen('hostname', 'r').read()
hostname = 'CrossCopy'
root.title('crosscopy on ' + hostname)
if client != 0:
# start the client
ccclient = CrossCopyClient(root)
else:
ccclient = None
# still need it to get the current paste selection
# but don't want it to appear
root.withdraw()
if server != 0:
# start the web server
try:
ccserver = CrossCopyServer(port)
except socket.error, msg:
print "Cannot bind to port %s: %s" % (port, msg)
# whatever ...
if client == 0 and server == 0:
sys.exit()
# must periodically check the server, if we have one
if server != 0:
root.after(200, check_ccserver)
root.mainloop()