first commit

This commit is contained in:
Jose Caban
2025-06-07 01:59:34 -04:00
commit 388ac241f0
3558 changed files with 9116289 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

BIN
CS2335/lab5/Images/Bold.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

BIN
CS2335/lab5/Images/Lock.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

BIN
CS2335/lab5/Images/Save.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

BIN
CS2335/lab5/Images/grin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

BIN
CS2335/lab5/Images/wink.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -0,0 +1,65 @@
CS2335 - Spring 2004 Lab 5 - NetTxt Xtreme
=============================================================================
README
=============================================================================
DIRECTIONS:
This form must be filled out and submitted with the rest of your files for
this lab. For each item replace the underscore characters ('_') with the
proper information. If you need more lines than those shown, feel free to
add them.
=============================================================================
1. Team Members:
Name: __________________________
GTNum: gt_____
Name: __________________________
GTNum: gt_____
Name: __________________________
GTNum: gt_____
Name: __________________________
GTNum: gt_____
2. Compilation Instructions:
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
3. Instructions for Running the Program:
____________________________________________________________
____________________________________________________________
____________________________________________________________
4. Known Bugs:
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
5. Extra Credit Attempted & Name of TA Who Approved If Not From
Lab File:
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
6. Testing/Development Environments (Include OS):
[REMINDER: This lab will be graded on the RedHat systems in
the States Lab.]
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
7. Comments:
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________

View File

@@ -0,0 +1,358 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><TITLE>Lab 5. NetTxt Xtreme (Lab Only)</TITLE><link rel="stylesheet" href="http://www.cc.gatech.edu/classes/AY2003/cs2335_spring/labs/style.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.59.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="chapter" lang="en"><div class="titlepage"><div><h2 class="title"><a name="id2748662"></a>Chapter<EFBFBD>5.<2E>
NetTxt Xtreme -- A networked text editor.
</h2></div><div><div class="author"><h3 class="author">Andrew Pilsch</h3></div></div><div><div class="author"><h3 class="author">Hemal Shah</h3></div></div><div><div class="author"><h3 class="author">Ryan Seekely</h3></div></div><div><div class="revhistory"><table border="1" width="100%" summary="Revision history"><tr><th align="left" valign="top" colspan="3"><b>Revision History</b></th></tr><tr><td align="left">Revision 1.1</td><td align="left">2004.02.12</td><td align="left">JC4</td></tr><tr><td align="left" colspan="3">Revisions made, image added.</td></tr><tr><td align="left">Revision 1.0</td><td align="left">2004.02.07</td><td align="left">ATP</td></tr><tr><td align="left" colspan="3">Initial Draft of the Lab</td></tr></table></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><a href="lab5.html#id2792118">1. Introduction</a></dt><dd><dl><dt><a href="lab5.html#id2792123">1.1. Overview of NetTxt Xtreme</a></dt><dt><a href="lab5.html#id2792150">1.2. User Story</a></dt><dt><a href="lab5.html#id2792225">1.3. A Screen Shot</a></dt></dl></dd><dt><a href="lab5.html#id2792260">2. Requirements</a></dt><dd><dl><dt><a href="lab5.html#id2792266">2.1. Locking Mechanism and Sections</a></dt><dt><a href="lab5.html#id2792358">2.2. Server Responsibilities</a></dt><dt><a href="lab5.html#id2791919">2.3. Chat System</a></dt><dt><a href="lab5.html#id2791957">2.4. Client Editing </a></dt><dt><a href="lab5.html#id2792769">2.5. More on Updating Sections</a></dt><dt><a href="lab5.html#id2792386">2.6. File Importing (and New Document Creation)</a></dt><dt><a href="lab5.html#id2792450">2.7. File Exporting</a></dt></dl></dd><dt><a href="lab5.html#id2792483">3. Deliverables</a></dt><dt><a href="lab5.html#id2793448">4. Extra Credit</a></dt></dl></div><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="http://www.cc.gatech.edu/classes/AY2003/cs2335_spring/labs/images/warning.png"></td><th align="left">Warning</th></tr><tr><td colspan="2" align="left" valign="top"><p>
This lab is due on WebCT before 2004.02.27 08:00
<span class="emphasis"><em>(that means turn it in no later than 7:59am)</em></span>
</p><p>
*** DO NOT WAIT UNTIL THE LAST MINUTE TO SUBMIT YOUR ASSIGNMENT ***
</p></td></tr></table></div><div class="section" lang="en"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2792118"></a>1. Introduction</h2></div></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792123"></a>1.1. Overview of NetTxt Xtreme</h3></div></div><p>
NetTxt Xtreme is a collaborative, on-line text editing
community. It is a system whereby multiple, distributed users
can open and collaboratively edit documents using the power of
cyberspace. </p><p>
NetTxt Xtreme will be significantly more advanced than previous
assignments, but build on many of the same concepts. There are
many requirements, so read carefully. We do not constrain the
design of your system, only the functionality requirements that
<span class="emphasis"><em>must</em></span> be met.
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792150"></a>1.2. User Story</h3></div></div><p>
Joe User logs into the system. Joe finds himself in the Global
chat room for the entire system. By browsing the server's list of
collaborative files and chatting with his peers, he can ascertain what
file he would like to edit.</p><p>After Joe User has selected a file, he chooses that file from
the community file browser. Joe can also choose to create a new file
that the community can work on. Today, though, Joe would like to work
on an already existing file. When he connects to the file he wants to
edit, he then sees a list of the various editable sections of that
document. (Think of sections as being analogous to chapters in a
novel.) Joe can chose to create a new section for a document or edit
a section that is not already locked. Joe choses to edit a section of
the document that is not already in use.</p><p>The server notes that Joe has locked that section of the file
and tells Joe's client to display a text editor for that section.
When Joe is done editing his section, he can click &quot;save&quot; and the
changes he made will be committed to the system.</p><p>Jane User, Joe's long-lost cousin, is also editing Joe's
document. She notices Joe is editing a section and that he has been
doing so for over an hour. She tells the client that she would like
to see the current state of Joe's section. The server then grabs
Joe's section out of his editor window and updates Jane's local
display. Jane likes what Joe has done and decides to create a local
copy of the entire document. Jane types Joe a compliment on his work
that Joe sees in his local file chat-room. She tells her client that
she would like to export a copy to her system. The client then
creates a copy of the document on her system from what she has, and
Jane reads through it using her HTML web browser.</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792225"></a>1.3. A Screen Shot</h3></div></div><p>
Here is a <span class="bold"><b>simplified</b></span> version of what
the client's editing window <span class="bold"><b>might</b></span>
look like. Your final version will differ significantly.
</p><div align="center"><img src="./Lab5_ScreenShot.gif" align="middle"></div></div></div><div class="section" lang="en"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2792260"></a>2. Requirements</h2></div></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792266"></a>2.1. Locking Mechanism and Sections</h3></div></div><p>
Each file that is being worked on should be divided into
sections that may be edited by the user. Only one user may
work on a particular section at any given time, and that
section should be considered locked until released by said
user. A user, however, may work on more than one section at
a time, and it is the server's responsibility to track which
sections are locked (by whom) and allowed to be edited.
Sections are not required to be embedded. In other words, a
section does not need to have the ability to contain other
sections (this is an extra credit opportunity, however).
</p><p>
When a new document is started, it is assumed that there are no
existing sections. A user's client should have the ability to
both create new sections, and edit existing, non-locked sections.
A section should have the following attributes:
</p><div class="itemizedlist"><ul type="bullet"><li style="list-style-type: disc">
A <span class="bold"><b>unique key</b></span> that identifies
the section <span class="emphasis"><em>(The key may be just a simple ID number
or a text string of the section name -- it's up to
you.)</em></span></li><li style="list-style-type: disc">
A <span class="bold"><b>position</b></span> which indicates
the order the sections should appear on the client view. The
position of a section may be changed, but no two sections
should ever share the same position.
</li><li style="list-style-type: disc">
The <span class="bold"><b>current user</b></span> (if any) that
has the section locked, to prevent others from editing it.
</li><li style="list-style-type: disc">
A <span class="bold"><b>time-stamp</b></span> which displays
the length of time since the section has gone unedited (e.g.
&quot;this section un-edited for 2 days, 3 hours, 27 minutes&quot;), or
the time the section has been locked by a user (e.g. &quot;this
section locked by 'TxtWiz37' for 18 minutes&quot;), depending on
the appropriate situation.
</li></ul></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792358"></a>2.2. Server Responsibilities</h3></div></div><p>
The Server must be multi-threaded and connect multiple users as always.
The Server must first accept connections and then login users by
letting the client choose a handle/screen-name which the Server ensures
is unique (otherwise, the client must re-prompt). Chat room functionality
will be handled by the Server as well.
</p><p>
The Server will handle all files for NetTxt Xtreme. It will manage
the updates/posts to a document, creation of a new document, and
receive files from the client which the Server will then import
into NetTxt Xtreme section format. The Server will also provide
the client with a list of all available files and those that are
currently open by other users. The Server will also save
open files to its local file system with the latest updates it
has either on an unlocking of a section or by client request.
</p><p>
The server must have a graceful way of exiting (one possible way
would be to have a GUI console that pops up while the server is
running that has a &quot;disconnect server&quot; button). When the server
exits it needs to save a current copy of the file on the server
(in a pre-determined location).
</p><p>
<span class="bold"><b>Suggestion:</b></span> If you have a GUI
&quot;console&quot; that controls the server, you may wish to use it to
permit the user to choose which port the server uses and
the location where the files are to be saved (remember to
include reasonable default values for these).
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2791919"></a>2.3. Chat System</h3></div></div><p>
The chat system for NetTxt Xtreme is vital to the collaborative
effort. The chat system required will be of the global and chat
room style.
</p><p>
All users, from the time they are logged in to the server to the
time they disconnect, will have a unique handle/scree-name and
will join the global chat room. The UI should provide a list of
all users currently in the global chat room and allow for chat
room messaging.
</p><p>
When a user opens a particular file or creates one, that user
enters a new chat room with all other users currently working
on that particular file. The UI should provide a list of all
users currently working on that file and allow for chat room
messaging in an area separate from the global chat room.
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2791957"></a>2.4. Client Editing </h3></div></div><p>
Upon joining a server and choosing a document to work on, a client should
have the ability to create a new section to work on, or editing any existing
section. Either selection (assuming the selected section was unlocked or new)
should bring up an editing window which allows the user to edit the contents
of a section. The section should be considered locked by the server, and no
other clients should be allowed editing capabilities to the section until the
locking user releases the section. If a user attempts to lock/edit an already
locked section, an indication should be made to the client that the section
is currently locked and NO editing window should be presented.
</p><p>
When working on a section, the user should have the capability to Post the
changes the user has made, which would tell the server to accept the changes
made by the user and then update all of the currently connected clients.
The user should be allowed to continue working on the section until he chooses
to Release the section. A Release would perform the operation of a Post and
unlock the section to allow other users to edit it. A client should also be able
to unlock the section disregarding any changes that may have been made.
</p><p>
The client should have the following editing capabilities <span class="emphasis"><em>(These should
be able to be applied by the user by highlighting a section of text and clicking
the appropriate icon -- much like other editing programs)</em></span>:
</p><div class="itemizedlist"><ul type="bullet"><li style="list-style-type: disc">
The ability to bold, italic, or underline any specified text in a section
</li><li style="list-style-type: disc">
Multiple fonts
</li><li style="list-style-type: disc">
Colorized text with a full array of colors
</li><li style="list-style-type: disc">
Alignment of text, such as Center, Left or Right
</li><li style="list-style-type: disc">
Different font sizes
</li></ul></div><p>
As you can tell, the requirements resemble those that are already easily
supported by HTML, and we once again highly recommend using HTML with the
combination of multiple JEditPanes. Although, the editing window does not
need to support a rendered view and may just show the HTML tags in conjunction
with the text for the user to edit.
</p><p>
The client should at all times display the most updated version (since
that particular client updated last) of the document, fully rendered (i.e.
if you are using HTML, no bold tags should be displayed, but rather the text
should be <span class="emphasis"><em> bold'ed </em></span>). The view should obey the order
specified by each sections position.
</p><p>
Remember as well, the client should be allowed to request updates on any
given section (or all sections), which should immediately be reflected in
the rendered view of the client's document.
</p><p>
Finally, the client should present visually to the user the following properties
of each section
</p><div class="itemizedlist"><ul type="bullet"><li style="list-style-type: disc">
An indication if the section is locked, and by which user
</li><li style="list-style-type: disc">
The key that uniquely identifies the section
</li><li style="list-style-type: disc">
A flag that indicates if the section has been edited/changed since the
client last updated the section
</li><li style="list-style-type: disc">
The amount of time the section has been locked by a user,
or the amount of time since the section has been edited
depending on the appropriate situation
</li></ul></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792769"></a>2.5. More on Updating Sections</h3></div></div><p>
The main purpose of NetTxt Xtreme is to allow for multiple
people to simultaneously collaborate on a text file. When one
user has a section locked, only that user can make changes to
that section. However, other users may want to view that same
locked section, and should be able to do so by asking for an
update from the server, which will retrieve the current text
of that section and send it to the requesting user only.
</p><p>
Your UI should display a time-stamp of the last time a
particular section was updated. The UI must give some
indication to the user that a section has been changed by its
owner since the last time the user updated it. You must be able
to request an update of locked sections from the server and
properly display those updated sections. You should also be able
to request that all locked sections not under your control be
updated.
</p><p>
The client should also be able to post a section that a user
is currently working on, either manually through the UI or
when the client unlocks a particular section. That section
should then be updated on all other clients and on the server.
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792386"></a>2.6. File Importing (and New Document Creation)</h3></div></div><p>
When creating a new file in NetTxt Xtreme, the user
shall be given two options: creating a blank document or
importing a file. When creating a blank document, the
user shall be able to add sections, just as in a regular
document.
</p><p>
You are required, also, to implement a basic file
importer. This importer shall be able to read in a
plain text file (you should assume a standard ASCII file
with unix line termination, i.e. using '\n' characters)
and, using some scheme that is up to you, be able to
break it into sections (<span class="bold"><b>Note:
creating one section for the entire document is not
a valid scheme</b></span>).
One such scheme would be to break the document into
sections based on paragraphs, in other words,
every time you encounter two new lines (i.e. &quot;\n\n&quot;
in the file), start a new section.
</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="http://www.cc.gatech.edu/classes/AY2003/cs2335_spring/labs/images/important.png"></td><th align="left">Important</th></tr><tr><td colspan="2" align="left" valign="top"><p>
The file to be imported is going to be located
on the local computer of the client. You will
have to build some mechanism to get the file
data to the server so that it can be stored
as a new collaborative document within the
NetTxt Xtreme system.
</p></td></tr></table></div><p>
See the extra credit section for points you can earn
by implementing a more complicated importer.
</p></div><div class="section" lang="en"><div class="titlepage"><div><h3 class="title"><a name="id2792450"></a>2.7. File Exporting</h3></div></div><p>
Sometimes, a user may want a copy of the complete file
on their local system. In order to facilitate this, you
need to give the users the ability to export a copy of
the file they are currently editing. Exporting will
produce a document that is a properly formatted HTML
document conforming to the current state of the
document, as the user currently sees it.
<span class="bold"><b>This is very important.</b></span>
File Exporting should produce a copy of the document
based on any sections the user may have updated that
differ from the server copy.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2792483"></a>3. Deliverables</h2></div></div><p>You must submit the following things:
</p><div class="itemizedlist"><ul type="bullet"><li style="list-style-type: disc">
All source code and libraries
needed to run your program.
</li><li style="list-style-type: disc">
The Ant build-file (build.xml), which needs
to contain the following targets (with the
appropriate dependencies):
<div class="itemizedlist"><ul type="disc"><li><span class="bold"><b>runclient</b></span> -
Runs the client program <span class="emphasis"><em>this
should be the default target</em></span></li><li><span class="bold"><b>runserver</b></span> -
Runs the server program
</li><li><span class="bold"><b>build</b></span> -
Compiles your program
</li><li><span class="bold"><b>checkstyle</b></span>
- Runs Checkstyle on your source code
</li><li><span class="bold"><b>pmd</b></span>
- Runs PMD on your source code
</li><li><span class="bold"><b>jar</b></span> -
Creates an executable Jar of your
program
</li><li><span class="bold"><b>javadoc</b></span>
- Creates the JavaDoc for your program
<span class="emphasis"><em>(NOTE: JavaDoc must not
produce any errors/warnings to receive
credit)</em></span></li><li><span class="bold"><b>clean</b></span>
- Removes all files created from all
other targets
</li></ul></div></li><li style="list-style-type: disc">
A completed README file (see &quot;README.txt&quot;
in the supplemental files provided with
the lab).
</li><li style="list-style-type: disc">
If you are seeking extra credit for
implementing other importers, please include
one example file in the format you seek to
import.
</li></ul></div><p>
The above items must be submitted in an archive file in one
of the following formats: zip, tar, jar, or gzip.
</p><p>
</p><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="http://www.cc.gatech.edu/classes/AY2003/cs2335_spring/labs/images/warning.png"></td><th align="left">Warning</th></tr><tr><td colspan="2" align="left" valign="top"><span class="bold"><b>
The following are part of the grading criteria for
this lab:
<div class="itemizedlist"><ul type="disc"><li>
-15 points (off the top) if your program fails
to pass PMD.
</li><li>
-15 points (off the top) if your program fails
to pass checkstyle.
</li><li>
-5 points (off the top) if your program fails
to pass JavaDoc without any errors or warnings.
</li><li>
-10 points (off the top) if the archive you
submit to WebCT has the wrong file extension.
</li><li>
AUTOMATIC ZERO if you fail to upload your
source code to WebCT in an archive (i.e.
uploading all of your files individually
is not allowed).
</li><li>
NO EXTRA CREDIT will be given it you fail to
document the extra credit options completed.
</li></ul></div>
</b></span></td></tr></table></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2793448"></a>4. Extra Credit</h2></div></div>
You may receive up to 20 points on your final grade for completing
any combination of the following extra credit options:
<div class="itemizedlist"><ul type="disc"><li>
Advanced Editing Mode (give users the option to use the
standard WYSIWYG editor or let them directly edit the
HTML source code and it should be easy to switch between the
two) - 5 pts.
</li><li>
Advanced Importing. You can get 5 pts each for
implementing any of the following schemes (you must
include a large (40 or more line) example of the format
you are attempting to import):
<div class="itemizedlist"><ul type="circle"><li>Rich Text Format</li><li>HTML</li><li>DocBook (XML file format)</li><li>
Some other format (e.g. LaTeX). <span class="emphasis"><em>E-mail
a format idea to a TA by 23:59 Wednesday, February 18
to get approval for another format.</em></span></li></ul></div></li><li>
Auto-saving Server - server auto-saves open files every
<span class="emphasis"><em>configurable</em></span> time interval. - 5pts.
</li><li>
Embedded locking. The ability to have nested locking
sections. An example of this would be if you were
editing a java source code file, a user could look the
whole class or just the methods. - 20pts.
</li><li>
Amazing UI - 5pts (this is decided by your TA)
</li><li>
Other ideas. If you have an idea you'd like to try for
extra credit, email it to a TA for approval by 23:59
Wednesday, February 18. The TA will determine how many
(if any) points are merited.
</li></ul></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="http://www.cc.gatech.edu/classes/AY2003/cs2335_spring/labs/images/important.png"></td><th align="left">Important</th></tr><tr><td colspan="2" align="left" valign="top"><p>
Unless arranged in advance (in writing), your TA will be grading this
assignment on the RedHat systems available in the States Lab and will
be using the Java tools provided in the &quot;~cs2335/&quot; directory. It is
YOUR responsibility to verify that your program will work on these
systems prior to submitting it.
</p></td></tr></table></div></div></body></html>

66
CS2335/lab5/README.txt Normal file
View File

@@ -0,0 +1,66 @@
CS2335 - Spring 2004 Lab 5 - NetTxt Xtreme
=============================================================================
README
=============================================================================
DIRECTIONS:
This form must be filled out and submitted with the rest of your files for
this lab. For each item replace the underscore characters ('_') with the
proper information. If you need more lines than those shown, feel free to
add them.
=============================================================================
1. Team Members:
Name: Jose Caban________________
GTNum: gtg184g
Name: Andrew Knight_____________
GTNum: gtg284h
Name: Vladimir Vurazov__________
GTNum: gtg308i
Name: Daniyar Zhanbekov_________
GTNum: gtg563g
2. Compilation Instructions:
____Type "ant build" to compile_____________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
3. Instructions for Running the Program:
____Start the server: "ant runserver"_______________________
____Connect as many clients as desired: "ant runclient"_____
____________________________________________________________
4. Known Bugs:
____The ServerUI works, however, does not execute all_______
commands correctly (start/stop do not work). However, this_
was left in as ant requires fork to run with the XML SAX____
Parser but cannot handle the regular console server with____
the fork option activated.
5. Extra Credit Attempted & Name of TA Who Approved If Not From
Lab File:
___Ultra Amazing UI_________________________________________
___HTML Importing___________________________________________
___Autosave_________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
6. Testing/Development Environments (Include OS):
[REMINDER: This lab will be graded on the RedHat systems in
the States Lab.]
___Development: Windows XP Professional_____________________
___Testing: Windows XP Professional, States Lab_____________
____________________________________________________________
____________________________________________________________
7. Comments:
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________

View File

@@ -0,0 +1,5 @@
<?xml version='1.0'?>
<documents numDocuments="1">
<document name="DocSuperName" id="1985508974" />
</documents>

View File

@@ -0,0 +1,14 @@
<html>
<head>
<title>HTMLInputTest</title>
</head>
<body>
<H2>Test HTML Input #1</H2>
<H3>Test Section #1</H3>
This is not formatted.
<H3>Test Section #2</H3>
This is not formatted either.
</body>
</html>

View File

@@ -0,0 +1,14 @@
<html>
<head>
<title>HTMLInputTest</title>
</head>
<body>
<H2>Test HTML Input #2</H2>
<H3>Test Section #1</H3>
This is not formatted.
</body>
</html>

View File

View File

View File

@@ -0,0 +1,38 @@
DocSuperName
...SecName1
THIS IS SECTION 1
...SecName2
THIS IS SECTION 2
...SecName3
THIS IS SECTION 3
...Linux vs. *BSD
The battle of the century.
Penguin versus non-Penguin
...How to make an omelette
1. go to states cluster
2. open up computer
3. remove heatsink
4. use aluminum foil pan to place on processor
5. Leave alone
6. Come back
7. Bring fork
8. Eat
9. Make sure the camera wasn't watching
10. Run
...SectionTheNext
There was a man named Vlad
who had quite a weird fad
he liked to say nub instead of newb
the end
...SectiontheNextTakeTwo
28
twenty-nine
THIRTY
THE MAN FROM KRASS LIVES AGAIN!
...SectionTheLast
Let's See
If
This
Crashes
The Server

132
CS2335/lab5/build.xml Normal file
View File

@@ -0,0 +1,132 @@
<project name="NetPaint" default="runclient" basedir=".">
<description>
Performs different build tasks for the NetText project.
</description>
<!-- Global Properties -->
<property name="user.name" location="Vladimir Urazov" />
<property name="src" location="src" />
<property name="docs" location="apidoc" />
<property name="doc_packages" value="nettext.*" />
<property name="classes" location="build" />
<property name="libs" location="lib" />
<property name="jarname_server" value="NetPaintServer.jar" />
<property name="jarname_client" value="NetPaintClient.jar" />
<property name="runClass_server" value="nettext.server.ServerRunner" />
<property name="runClass_client" value="nettext.client.ClientRunner" />
<property name="checkstyle_logfile" value="checkstyle_log.txt" />
<property name="pmd_logfile" value="pmd_log.html" />
<property name="pmd_rules" value="rulesets/basic.xml,rulesets/unusedcode.xml,rulesets/design.xml,rulesets/imports.xml" />
<!-- Paths -->
<property name="pmd_path" location="/net/hu15/cs2335/java/pmd/lib" />
<property name="checkstyle_path" location="/net/hu15/cs2335/java/checkstyle" />
<path id="pmd.classpath">
<fileset dir="${pmd_path}">
<include name="*.jar"/>
</fileset>
</path>
<path id="checkstyle.classpath">
<fileset dir="${checkstyle_path}">
<include name="checkstyle-all-3.3.jar" />
</fileset>
</path>
<!-- Taskdefs -->
<taskdef resource="checkstyletask.properties" classpathref="checkstyle.classpath" />
<taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath" />
<!-- Targets -->
<target name="init">
<!-- Create the time stamp -->
<tstamp />
</target>
<target name="build" depends="init" description="Compiles the program">
<!-- Make sure the necessary directory structure exists -->
<mkdir dir="${classes}" />
<!-- Compile -->
<javac srcdir="${src}" destdir="${classes}" />
<copy todir="${classes}/nettext/util">
<fileset dir="Images"/>
</copy>
</target>
<target name="javadoc" description="Creates JavaDoc for NetText">
<!-- Make sure the necessary directory structure exists -->
<mkdir dir="${docs}" />
<!-- Generate comments -->
<javadoc packagenames="${doc_packages}" sourcepath="${src}" destdir="${docs}" />
</target>
<target name="jar" depends="build" description="Package the compiled classes into a JAR file.">
<jar destfile="${jarname_server}" basedir="${classes}">
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Main-Class" value="${runClass_server}" />
</manifest>
</jar>
<jar destfile="${jarname_client}" basedir="${classes}">
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Main-Class" value="${runClass_client}" />
</manifest>
</jar>
</target>
<target name="runserver" depends="build" description="Start the server">
<java classname="${runClass_server}" fork="true">
<classpath>
<pathelement path="${classes}" />
</classpath>
</java>
</target>
<target name="runclient" depends="build" description="Start the client">
<java classname="${runClass_client}" fork="true">
<classpath>
<pathelement path="${classes}" />
</classpath>
</java>
</target>
<target name="checkstyle" description="Checks all of the source code with Checkstyle.">
<checkstyle config="${checkstyle_path}/docs/sun_checks.xml" failOnViolation="false">
<fileset dir="${src}" includes="**/*.java" />
<formatter type="plain" toFile="${checkstyle_logfile}" />
</checkstyle>
</target>
<target name="pmd" description="Run PMD against all source code files.">
<pmd rulesetfiles="${pmd_rules}">
<fileset dir="${src}" includes="**/*.java" />
<formatter type="html" toFile="${pmd_logfile}" />
</pmd>
</target>
<target name="all">
<antcall target="checkstyle" />
<antcall target="pmd" />
<antcall target="build" />
<antcall target="javadoc" />
</target>
<target name="clean">
<delete dir="${classes}" />
<delete dir="${docs}" />
<delete file="${jarname}" />
<delete file="${checkstyle_logfile}" />
<delete file="${pmd_logfile}" />
</target>
</project>

101
CS2335/lab5/build_jose.xml Normal file
View File

@@ -0,0 +1,101 @@
<project name="NetPaint" default="runclient" basedir=".">
<description>
Performs different build tasks for the NetText project.
</description>
<property name="src" location="src" />
<property name="classes" location="build" />
<property name="runClass_server" value="nettext.server.ServerRunner" />
<property name="runClass_client" value="nettext.client.ClientRunner" />
<!-- Targets -->
<target name="init">
<!-- Create the time stamp -->
<tstamp />
</target>
<target name="build" depends="init" description="Compiles the program">
<!-- Make sure the necessary directory structure exists -->
<mkdir dir="${classes}" />
<!-- Compile -->
<javac srcdir="${src}" destdir="${classes}" />
</target>
<target name="javadoc" description="Creates JavaDoc for NetText">
<!-- Make sure the necessary directory structure exists -->
<mkdir dir="${docs}" />
<!-- Generate comments -->
<javadoc packagenames="${doc_packages}" sourcepath="${src}" destdir="${docs}" />
</target>
<target name="jar" depends="build" description="Package the compiled classes into a JAR file.">
<jar destfile="${jarname_server}" basedir="${classes}">
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Main-Class" value="${runClass_server}" />
</manifest>
</jar>
<jar destfile="${jarname_client}" basedir="${classes}">
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Main-Class" value="${runClass_client}" />
</manifest>
</jar>
</target>
<target name="runserver" depends="build" description="Start the server">
<java classname="${runClass_server}" fork="true">
<classpath>
<pathelement path="${classes}" />
</classpath>
</java>
</target>
<target name="runclient" depends="build" description="Start the client">
<java classname="${runClass_client}" fork="true">
<classpath>
<pathelement path="${classes}" />
</classpath>
</java>
</target>
<target name="checkstyle" description="Checks all of the source code with Checkstyle.">
<checkstyle config="${checkstyle_path}/docs/sun_checks.xml" failOnViolation="false">
<fileset dir="${src}" includes="**/*.java" />
<formatter type="plain" toFile="${checkstyle_logfile}" />
</checkstyle>
</target>
<target name="pmd" description="Run PMD against all source code files.">
<pmd rulesetfiles="${pmd_rules}">
<fileset dir="${src}" includes="**/*.java" />
<formatter type="html" toFile="${pmd_logfile}" />
</pmd>
</target>
<target name="all">
<antcall target="checkstyle" />
<antcall target="pmd" />
<antcall target="build" />
<antcall target="javadoc" />
</target>
<target name="clean">
<delete dir="${classes}" />
<delete dir="${docs}" />
<delete file="${jarname}" />
<delete file="${checkstyle_logfile}" />
<delete file="${pmd_logfile}" />
</target>
</project>

View File

@@ -0,0 +1,7 @@
<html>
<head>
<title>Document4</title>
</head>
<body>
<H2>Document4</H2>
<H3>

View File

@@ -0,0 +1 @@
Document3

View File

@@ -0,0 +1 @@
Document2

View File

@@ -0,0 +1 @@
Document1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

View File

@@ -0,0 +1,76 @@
NetTxt Networking Protocol.
The network messages will be sent between the server and the client in pure text format, for ease of coding and debugging. Some of the messages can only be sent from the server to the client and others - only the other way around, while others still can be sent by the server or by the client.
The messages will be identified by an all-caps message type in the front of the message, and the different parts of each message will be delimited by the escaped unit separator character ( \037 ).
The following things will need to be negotiated over the network:
1. User joining/quitting the server.
2. Chat messages (of the public and private variety).
3. List users in a chat room (public or private).
4. List documents on the server.
5. List sections in a document. (Maybe instead the user should just get the whole document when he opens it up?)
6. Create a new document.
7. Create a new section in a document.
8. Request lock on a section.
9. Release lock on a section.
10. Notify the server that we are starting to view / stopped viewing a document.
11. Request latest version of a section (document?)
12. Transmit latest version of a section (document?)
The messages that will need to be sent are as follows*:
SRVE - Server error. Rejection, drop, server quitting, etc. Format:
SRVE^message
HELO - User is joining the server. Format:
HELO^username
QUIT - User is quitting the server gracefully. Format:
QUIT^username
CHAT - User is sending a chat message. Format:
CHAT^username^docId^text
Here, the docId parameter specifies which chat room the message belongs to.
ULST - The list of users in a chat room. Format:
ULST^docId^usrCount^username1^username2^...
Here, the docId parameter specifies which chat room the list belongs to, and the usrCount parameter specifies how many users there are in the chat room. That one parameter is only needed for parsing purposes.
DLST - The list of documents available on the server. Format:
DLST^docCount^docId1^docName1^docId2^docName2^...
Here, docCount specifies how many documents are in the list (for parsing purposes only), docIdN specifies the unique ID of the Nth document, and docNameN specifies the name of the Nth document.
DCMT - Transfers a document either from the server to the client or from the client to the server. Format:
DCMT^docId^docName^loaded(1|0)^secCount^username^secId^secOrder^stamp^locked(0|1)^secName^secContents
If the load flag is one, then each section also contains all the information pertinent to each section. If it set to 0, then only the section names and ids are transferred.
SCTN - Transfers a section of a document. Format:
SCTN^username^docId^secId^secOrder^stamp^locked(0|1)^secName^secContents
username is the name of the author of the latest update. docId is the id of the document in which the section appears. secId is the id of the section - just a hash key of its name, basically. secOrder is the order in which the section appears in the document. stamp is the timestamp. locked is 0 if the section is unlocked and 1 if it is locked. secName is the name of the section. secContents is the contents of the section.
RMSC - Remove section from a document. Format:
RMSC^username^docId^secId
LOCK - Requests a lock on a section. Format:
LOCK^username^docId^secId
The order in which the section appears in the document is sufficient for the secId.
ULCK - Releases a lock on a section. Format:
ULCK^username^docId^secId
VIEW - Notifies the server that the user has started viewing a document. Format:
VIEW^username^docId
UVEW - Notifies the server that the user has stopped viewing a document. Format:
UVEW^username^docId
UPDT - Requests the latest version of a document. Format:
UPDT^username^docId
* Note that here the ^ character serves to represent the unit separator character, which is \037.

View File

@@ -0,0 +1,61 @@
The server will have a directory termed "the repository" that will contain all of the documents on that server. The files will be arranged as follows:
d) root_dir
|
+- f) doc1.xml
|
+- f) doc2.xml
|
+- f) doc_list.xml
d) here denotes a directory, and f) - a file.
doc_list.xml will be a master document list that will contain a list
of all documents and the names of the directories in which they
reside. Each document will reside in a directory of its own. The
doc_list.xml file will have the following structure:
<documents>
<document id="0001" name="Introduction to NetPaint" />
<document id="0002" name="Introduction to NetTxt" />
<document id="0003" name="NetTxt: Advanced Topics" />
</documents>
The ID will be the hash code of the name of the document and has to
be unique (no two documents with the same name allowed).
docNNNN.xml will be created for each document and will contain the
document itself as well as the list of sections and their contents:
<document name="NetTxt Server File Structure" id="0001">
<section id="0001" name="Introduction" editor="Vladimir" time="2004-02-15 13:39" position="1">
The section stuff goes in here.
</section>
<section id="0002" name="Directory Structure" editor="Vladimir" time="2004-02-15 13:40" position="2">
The section stuff goes in here.
</section>
</document>
The section tags will contain the text of each section. Each
paragraph will be contained within the <p> tags which will specify
the alignment of the paragraph. The <p> tags can contain <b>, <i>,
and <u> tags to denote formatting, as well as the <font> tags which
will allow one to choose font faces and <color> tags which will
allow one to choose colors. The format of the file will be as
follows:
<section>
<p align="left">
The server will have a directory termed <i>"The Repository"</i> that will contain all of the documents on that server. The files are arranged as follows:
</p>
</section>
This file structure will simplify the file reading/writing process
quite a bit. Making a list of documents available from the server
still wouldn't be a problem even, since we would have that list
available form the master doc_list.

View File

@@ -0,0 +1,14 @@
Tuesday
February 17
Have the network messages implemented.
Have the file IO for the NetText formats implemented, as well as for the document list.
Have the basic user and chat functionality working on the server.
Thursday
February 19
Finish up the server.
Implement the UI.
Friday
February 20
Finish the Client architecture design.

View File

@@ -0,0 +1,71 @@
Bugs:
Somehow when we start the server UI, the server starts automatically,
even if we don't push the "Start" button. I don't particularly mind
this now, as it makes the debugging one click faster, but it is a bug
and needs to be fixed. Low Priority.
Sometimes the document list doesn't get updated on the client... I am
not sure why this may be, as I cannot reproduce this one a stable
basis.
The client list in the chat panel looks ugly. It either takes up too
much space, or too little. Fix it!
In all the JLists in general, the text is stuck agains the left
edge. Would be good to add a little margin there.
Testing:
Untested:
NetTextDocumentReader.java - Jose (need client/server)
Everything else, pretty much, too.
Implementation:
Implement network messages. (Andrew, Daniyar)
+ Implement the regular server message. (Maybe do the same
abstraction as in netpaint - AbstractServerMessage with the
children - GenericServerMessage, and ServerErrorMessage.) When I
was writing the protocol, I thought we never used the regular
server message in netpaint, and so exclueded it from the
protocol. While writing the networking code, I remembered what it
was I needed to use this generic message for, and I still need it
here.
Implement file IO. (Jose)
-Implement
Implement document structure. (Jose)
Implement server functionality. (Vladimir)
+ Implement the framework for managing clients - adding, dropping.
+ Implement the Client class.
+ Need to add the document list to the client class when the
document list class becomes available.
+ Implement the client list stuff.
o Implement the chat functionality.
o Implement the document handling functionality.
o Implement Server settings with default values.
+ Still need to add here the defaults for the repository and the
autosave delay.
Implement server UI. (Vladimir)
+ Implement the interactive user list.
o Implement the kick user button.
Shared UI
+ Implement client list.
Client UI:
o Implement it so when the client receives a "duplicate username"
message, it doesn't freak out and drop the connection...
Miscellaneous:
Fill in the package.html placeholder descriptions with real information.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,418 @@
package nettext.client;
import java.util.List;
import java.util.Vector;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
import nettext.messaging.AbstractMessage;
import nettext.client.networking.ClientNetworking;
import nettext.client.gui.ClientUI;
import nettext.document.Document;
import nettext.file.ASCIIDocumentReader;
import nettext.file.HTMLDocumentReader;
import nettext.file.ASCIIOutputHandler;
import nettext.file.HTMLOutputHandler;
/**
* Class Client: This singleton class will tie everything together -
* the networking, the ui, etc.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the Client class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public final class Client {
/**
* YASLI: Yet Another SingLeton Instance.
*/
private static Client instance;
/**
* This is the name under which the user is connected to the
* server. If no name was provided, a generic name will be used.
*/
private String userName;
/**
* The object that encapsulates the networking functionality for the
* client.
*/
private ClientNetworking network;
/**
* This guy will be used to handle all of the message processing for
* the client.
*/
private MessageProcessor processor;
/**
* Creates a new <code>Client</code> instance.
*/
private Client() {
userName = null;
network = new ClientNetworking();
processor = new MessageProcessor();
}
/**
* That's right... Another singleton! God, am I getting sick of
* reimplementing them over and over! Why? Why doesn't java 1.4 have
* templates, so I could just make ONE bloody singleton class and
* inherit from a templated copy of it? :(
*
* @return a <code>Client</code> value
*/
public static Client getInstance() {
if (instance == null) {
instance = new Client();
}
return instance;
}
/**
* Returns the name under which the user is connected to the server.
*
* @return a <code>String</code> value
*/
public String getUsername() {
return userName;
}
/**
* Gives the user a new name.
*
* @param name a <code>String</code> value
*/
protected void setUsername(final String name) {
this.userName = name;
}
/**
* Attempts to connect to the server specified in the parameters.
*
* @param host The hostname of the server to connect to.
* @param port The port at which we want to connect to the server.
* @param username The username that we want to use for this connection.
* @return True if the connection was successful, and false if it failed.
*/
public boolean connectToServer(final String host,
final int port,
final String username) {
boolean result = false;
List data = new Vector();
AbstractMessage message = null;
if (username != null) {
setUsername(username);
}
//Connect to the server
result = network.connect(host, port);
if (!result) {
//Could not connect to the server...
//Tell ClientUI to issue a warning saying the connection failed.
ClientUI.getInstance().showWarning("Connection Failed",
"Could not connect to the server.");
return false;
}
//Issue a helo message
data.add(getUsername());
message = MessageFactory.getInstance()
.makeMessage(MessageSettings.JOIN_TYPE, data);
result = sendMessage(message);
if (!result) {
//Failed to send the HELO message
if (ClientSettings.VERBOSE) {
System.out.println("Client: Could not send HELO message...");
}
//Tell ClientUI to issue a warning
ClientUI.getInstance().showWarning("Connection Failed",
"Could not send a join message to"
+ " the server.");
network.shutDown();
return false;
}
return true;
}
/**
* This function will issue a QUIT message to the server and then
* tell client networking to shut down.
* @param clean Specifies whether or not a QUIT message should be
* issued. If this parameter is false, the client will just close
* the socket.
*/
public void disconnectFromServer(final boolean clean) {
List data = new Vector();
AbstractMessage message = null;
if (!network.isConnected()) {
return;
}
if (clean) {
//Issue a quit message:
data.add(getUsername());
message = MessageFactory.getInstance()
.makeMessage(MessageSettings.QUIT_TYPE, data);
sendMessage(message);
}
//Shut down networking:
network.shutDown();
ClientUI.getInstance().hideDocumentListFrame();
}
/**
* Returns true if the client is currrently connected to the server,
* and false if he is not.
*
* @return a <code>boolean</code> value
*/
public boolean isConnected() {
return network.isConnected();
}
/**
* Sends a message to the server. If the send succeeds, returns
* true. Otherwise returns false.
*
* @param message an <code>AbstractMessage</code> value
* @return a <code>boolean</code> value
*/
public boolean sendMessage(final AbstractMessage message) {
if (message == null) {
return false;
}
if (!network.isConnected()) {
return false;
}
network.sendMessage(message);
return true;
}
/**
* This will be called when the client wishes to create a new
* document.
*/
public void createDocument() {
//See if we are connected
if (!isConnected()) {
return;
}
//Ask the user for a document name
String name = ClientUI.getInstance()
.showInputDialog("Choose Document Name",
"Please choose the name for your new document:",
"Document1");
if (name == null) {
return;
}
//Tell the server we have created a new document. It should either
//tell us that the document has been added by sending us a DCMT
//message, or that one with the same name already exists.
List data = new Vector();
Document doc = new Document();
doc.setDocumentName(name);
doc.setDocumentLoaded(true);
doc.updateDocument();
data.add(doc);
sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, data));
}
/**
* Shows the open dialog first and then performs the loading of the
* document, after which, this document is send over to the server
* for approval.
*/
public void importDocument() {
//written by Jose Caban
//Check for connection
if (!isConnected()) {
return;
}
//Pop up the thingamabob to select the file
String fileName = ClientUI.getInstance().browseLoadFileName(null);
if (fileName == null) {
return;
}
//Check the file type
if (fileName.endsWith(".txt")) {
/* Load ASCII */
ASCIIDocumentReader asciiDocReader = new ASCIIDocumentReader();
if (!asciiDocReader.initialize(fileName)) {
System.err.println("Error Loading Document");
System.err.flush();
ClientUI.getInstance()
.showError("File I/O Error",
"Error accessing the File");
return;
}
Document docImportMe = asciiDocReader.readDocument();
if (docImportMe == null) {
System.err.println("Error loading the document");
return;
}
asciiDocReader.cleanUp();
docImportMe.updateDocument();
List v = new Vector();
v.add(docImportMe);
sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, v));
} else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
/* Load HTML */
HTMLDocumentReader htmlDocReader = new HTMLDocumentReader();
if (!htmlDocReader.initialize(fileName)) {
System.err.println("Error Loading Document");
System.err.flush();
ClientUI.getInstance()
.showError("File I/O Error",
"Error accessing the File");
return;
}
Document docImportMe = htmlDocReader.readDocument();
if (docImportMe == null) {
System.err.println("Error loading the document");
return;
}
htmlDocReader.cleanUp();
List v = new Vector();
v.add(docImportMe);
sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, v));
} else {
ClientUI.getInstance()
.showError("File Type Unsupported",
"The file you selected is not Supported");
return;
}
}
/**
* Export a Document
* @param docExportMe the Document to export
*/
public void exportDocument(Document docExportMe) {
String fileName = ClientUI.getInstance().browseSaveFileName(null);
if (fileName == null) {
return;
}
fileName = fileName.substring(0, fileName.length() - 4);
if (ClientSettings.VERBOSE) {
System.out.println("Export file: " + fileName);
}
//Check the file type
if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
HTMLOutputHandler htmlOutputHandler = new HTMLOutputHandler();
htmlOutputHandler.initialize(fileName);
if (!htmlOutputHandler.writeToDisk(docExportMe)) {
ClientUI.getInstance().showError("Error Writing File",
"The system encountered an error writing the file to disk."
+ " This is most likely Linux's fault");
}
} else {
ASCIIOutputHandler asciiOutputHandler = new ASCIIOutputHandler();
asciiOutputHandler.initialize(fileName);
if (!asciiOutputHandler.writeToDisk(docExportMe)) {
ClientUI.getInstance().showError("Error Writing File",
"The system encountered an error writing the file to disk."
+ " This is most likely Linux's fault");
}
asciiOutputHandler.cleanUp();
}
}
/**
* This function receives the message from the server. It needs to
* check the type of message first. Then, if the message is a
* graphics message, this should send it to the message list, and
* tell the graphics panel to rerender. If it is a chat message, it
* should be sent to the message list, and then to the chat
* panel. Etc.
*
* @param message an <code>AbstractMessage</code> value
*/
public void processMessage(final AbstractMessage message) {
processor.processMessage(message);
}
/**
* This function will be called by the server listener when the
* server drops the connection. It will take appropriate steps to
* shut down the connection and notify the user of the problem.
*/
public void serverQuit() {
ClientUI.getInstance().showWarning("Server Lost",
"The connection to the server has "
+ "been lost...");
network.shutDown();
}
/**
* Shuts down the client.
*/
public void shutDown() {
//FIXME: Implement a clean shutdown.
System.exit(0);
}
}

View File

@@ -0,0 +1,54 @@
package nettext.client;
import nettext.client.gui.ClientUI;
/**
* Class ClientRunner: This will run the client.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the ClientRunner class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public final class ClientRunner {
/**
* Creates a new <code>ClientRunner</code> instance.
*/
private ClientRunner() { }
/**
* Create the GUI and show it. For thread safety, this method
* should be invoked from the event-dispatching thread. This is
* purely for the chat testing main.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
//Start up the main window
ClientUI.getInstance().startMainWindow();
//Show the connection dialog:
ClientUI.getInstance().showConnectionDialog();
}
/**
* Main method for running the ClientRunner class.
*
* @param args a String array of command line arguments.
*/
public static void main(final String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

View File

@@ -0,0 +1,36 @@
package nettext.client;
/**
* Class ClientSettings: Contains some settings shared among all
* client classes.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 01, 2004) - Created the ClientSettings class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 01, 2004
*/
public final class ClientSettings {
/**
* This is the location where all the images used in the program
* will be located. Note that this is not to say: images downloaded
* during the sessions, but rather the images associated with the
* program - button icons, and such.
*/
public static final String IMAGE_LOCATION = "Images/";
/**
* Produce extra debug output?
*/
public static final boolean VERBOSE = false;
/**
* Creates a new <code>ClientSettings</code> instance.
*/
private ClientSettings() {
}
}

View File

@@ -0,0 +1,386 @@
package nettext.client;
import java.util.List;
import java.util.Vector;
import nettext.client.gui.ClientUI;
import nettext.client.gui.DocumentFrame;
import nettext.document.Document;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
import nettext.messaging.AbstractMessage;
import nettext.messaging.JoinMessage;
import nettext.messaging.QuitMessage;
import nettext.messaging.ChatMessage;
import nettext.messaging.DocumentListMessage;
import nettext.messaging.DocumentMessage;
import nettext.messaging.UserListMessage;
import nettext.messaging.ServerErrorMessage;
import nettext.messaging.GenericServerMessage;
import nettext.messaging.SectionMessage;
import nettext.messaging.UpdateRequestMessage;
/**
* Class MessageProcessor: This guy will simply do the message
* processing for the client. It's sort of a little state machine that
* will keep track of what's going on. It is essentially an
* inseparable part of the client, and the reason it lives in a class
* of its own is that the Client class is cluttered the way it is
* already and so extra message handling stuff would make it totally
* unreadabale.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the MessageProcessor class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public final class MessageProcessor {
/**
* Creates a new <code>MessageProcessor</code> instance.
*/
protected MessageProcessor() { }
/**
* Does the processing required for the message.
*
* @param message an <code>AbstractMessage</code> value
*/
public synchronized void processMessage(final AbstractMessage message) {
if (message == null) {
return;
}
if (message instanceof ServerErrorMessage) {
processServerError((ServerErrorMessage) message);
} else if (message instanceof GenericServerMessage) {
processGenericServerMessage((GenericServerMessage) message);
} else if (message instanceof JoinMessage) {
processJoinMessage((JoinMessage) message);
} else if (message instanceof QuitMessage) {
processQuitMessage((QuitMessage) message);
} else if (message instanceof ChatMessage) {
processChatMessage((ChatMessage) message);
} else if (message instanceof DocumentMessage) {
processDocumentMessage((DocumentMessage) message);
} else if (message instanceof SectionMessage) {
processSectionMessage((SectionMessage) message);
} else if (message instanceof UpdateRequestMessage) {
processUpdateRequestMessage((UpdateRequestMessage) message);
} else if (message instanceof DocumentListMessage) {
processDocumentListMessage((DocumentListMessage) message);
} else if (message instanceof UserListMessage) {
processUserListMessage((UserListMessage) message);
} else {
System.out.println("MessageProcessor: Unknown message type - "
+ message.getClass().getName());
}
}
/**
* This function will be called by the server listener when a server
* error message is received. It will check the message to see if it
* is fatal, and in case it is, it will shut down the
* connection. Otherwise, the connection will remain.
*
* @param message a <code>ServerErrorMessage</code> value
*/
public void processServerError(final ServerErrorMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
//Check if this is a username fault
String text = message.getServerMessage();
if (text.equals("Connection refused: Duplicate username exists on the "
+ "server.")) {
//If so, show a prompt for a new username and send a new helo message
String newName = ClientUI.getInstance()
.showInputDialog("Duplicate Username",
"A client with the username you selected\n"
+ "is already logged in to the server.\n"
+ "Please choose a new username:",
"-=" + Client.getInstance().getUsername() + "=-");
if (newName == null) {
Client.getInstance().disconnectFromServer(false);
}
List data = new Vector();
data.add(newName);
Client.getInstance().setUsername(newName);
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.JOIN_TYPE,
data));
} else {
//Otherwise, disconnect
ClientUI.getInstance().showError("Server Error",
"Received a message from the server: \""
+ message.getServerMessage() + "\"");
Client.getInstance().disconnectFromServer(true);
}
}
/**
* Processes the GenericServer message.
*
* @param message a <code>GenericServerMessage</code> value
*/
public void processGenericServerMessage(final GenericServerMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
ClientUI.getInstance().getDocumentListFrame().getChatPanel()
.receiveMessage(message);
}
/**
* Processes the Join message.
*
* @param message a <code>JoinMessage</code> value
*/
public void processJoinMessage(final JoinMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
ClientUI.getInstance().getDocumentListFrame().getChatPanel()
.receiveMessage(message);
}
/**
* Processes the Quit message.
*
* @param message a <code>QuitMessage</code> value
*/
public void processQuitMessage(final QuitMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
ClientUI.getInstance().getDocumentListFrame().getChatPanel()
.receiveMessage(message);
}
/**
* Processes a chat message.
*
* @param message a <code>ChatMesage</code> value
*/
public void processChatMessage(final ChatMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
int id = message.getDocId(); //The document id of the message
if (id == 0) {
//Public message
ClientUI.getInstance().getDocumentListFrame().getChatPanel()
.receiveMessage(message);
} else {
//Private message
DocumentFrame f = ClientUI.getInstance().getDocumentFrame(id);
if (f == null) {
System.out.println("MessageProcessor: Got a chat message for " + id
+ " and there is no such window...");
} else {
f.getChatPanel().receiveMessage(message);
}
}
}
/**
* Describe <code>processDocumentListMessage</code> method here.
*
* @param message a <code>DocumentListMessage</code> value
*/
public void processDocumentListMessage(final DocumentListMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
ClientUI.getInstance().showDocumentListFrame();
ClientUI.getInstance().getDocumentListFrame()
.getDocumentListPanel().updateList(message);
}
/**
* Processes the UpdateRequest message.
*
* @param message a <code>UpdateRequestMessage</code> value
*/
public void processUpdateRequestMessage(final UpdateRequestMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
int docId = message.getDocId();
DocumentFrame df = ClientUI.getInstance().getDocumentFrame(docId);
if (df == null) {
//Tough luck.
System.out.println("MessageProcessor: Could not find appropriate "
+ "document frame.");
return;
}
Document doc = df.getDocumentPanel().getDocument();
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Took document - " + doc);
System.out.flush();
}
List data = new Vector();
data.add(doc);
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE, data));
}
/**
* Processes the Document message.
*
* @param message a <code>DocumentMessage</code> value
*/
public void processDocumentMessage(final DocumentMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
ClientUI.getInstance().addDocumentFrame(message.getDocument());
}
/**
* Processes the Section message.
*
* @param message a <code>SectionMessage</code> value
*/
public void processSectionMessage(final SectionMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
//Check if we have a window with the section's document already open
DocumentFrame df = ClientUI.getInstance()
.getDocumentFrame(message.getDocSection().getDocumentId());
if (df != null) {
//Update the section list and the document:
Document d = df.getDocumentPanel().getDocument();
try {
d.getSections()
.removeSectionAt(message.getDocSection().getSectionOrder());
d.getSections().insert(message.getDocSection(),
message.getDocSection().getSectionOrder());
} catch (ArrayIndexOutOfBoundsException aioobe) {
d.getSections().add(message.getDocSection());
}
df.getDocumentPanel().setDocument(d);
df.getSectionListPane().setDocument(d);
//FIXME: If we have the section opened up, update that window, too.
//FIXME: If we have the section lcoked, open up an editing window.
}
}
/**
* Processes the UserList message.
*
* @param message a <code>UserListMessage</code> value
*/
public void processUserListMessage(final UserListMessage message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
int docId = message.getDocId();
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: updating user list for "
+ "document with ID - " + docId);
System.out.flush();
}
if (docId == 0) {
//This is for the public chat room.
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Updatig global chat room.");
System.out.flush();
}
ClientUI.getInstance().showDocumentListFrame();
ClientUI.getInstance().getDocumentListFrame()
.getChatPanel().updateUserList(message);
ClientUI.getInstance().getDocumentListFrame()
.getChatPanel().receiveMessage(message);
} else {
//Get the private chat room and send the message there.
DocumentFrame f = ClientUI.getInstance().getDocumentFrame(docId);
if (f == null) {
System.out.println("MessageProcessor: Got a user list message for "
+ docId + " and there is no such window...");
} else {
f.getChatPanel().updateUserList(message);
}
}
}
/**
* Processes the message.
*
* @param message a <code>Message</code> value
*/
/*
public void processMessage(final Message message) {
if (ClientSettings.VERBOSE) {
System.out.println("MessageProcessor: Processing the message: "
+ message.getClass().getName());
System.out.flush();
}
}
*/
}

View File

@@ -0,0 +1,504 @@
package nettext.client.gui;
import java.util.List;
import java.util.Vector;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.ImageIcon;
import javax.swing.JTextPane;
import javax.swing.JTextField;
import javax.swing.JScrollPane;
import javax.swing.text.Style;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import javax.swing.text.StyleConstants;
import javax.swing.text.BadLocationException;
import nettext.client.Client;
import nettext.util.ImageLoader;
import nettext.messaging.ChatMessage;
import nettext.messaging.JoinMessage;
import nettext.messaging.QuitMessage;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
import nettext.messaging.AbstractMessage;
import nettext.messaging.UserListMessage;
import nettext.messaging.AbstractServerMessage;
import nettext.messaging.AdministrativeMessage;
/**
* Class ChatPanel: The chat panel will contain the messages sent out
* by other clients. This can be used for the global as well as the
* local chatrooms.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the ChatPanel class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public class ChatPanel extends JPanel implements ActionListener {
/**
* This is where all of the chat messages received by the client are
* shown.
*/
private JTextPane contents;
/**
* This is where the user will type in the chat message.
*/
private JTextField inputField;
/**
* When this button is clicked, the message typed into the input
* field will be sent out.
*/
private JButton sendButton;
/**
* The panel that will contain the list of clients in this chat room.
*/
private ClientListPanel clientsPanel;
/**
* This specifies which document the chat room is associated with.
*/
private int documentId;
/**
* Creates a new <code>ChatPanel</code> instance. Takes in the
* document ID for the document with which the chat panel will be
* associated.
* @param docId an <code>int</code> value
*/
public ChatPanel(final int docId) {
super(new BorderLayout());
documentId = docId;
// this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
JPanel stuffPane = new JPanel(new BorderLayout());
JPanel inputPanel = new JPanel(new BorderLayout());
JScrollPane contentScrollPane = null;
clientsPanel = new ClientListPanel();
contents = createTextPane();
inputField = new JTextField();
sendButton = new JButton("Send");
contentScrollPane = new JScrollPane(contents);
contentScrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
contents.setEditable(false);
sendButton.setActionCommand("send");
sendButton.addActionListener(this);
inputField.addActionListener(this);
inputPanel.add(inputField, BorderLayout.CENTER);
inputPanel.add(sendButton, BorderLayout.EAST);
stuffPane.add(contentScrollPane, BorderLayout.CENTER);
stuffPane.add(inputPanel, BorderLayout.SOUTH);
this.add(stuffPane, BorderLayout.CENTER);
this.add(clientsPanel, BorderLayout.EAST);
}
/**
* Does all of the necessary initialization for the chat content text pane.
*
* @return a <code>JTextPane</code> value
*/
private JTextPane createTextPane() {
JTextPane result = new JTextPane();
StyledDocument sdoc = result.getStyledDocument();
addChatStyles(sdoc);
addImageStyles(sdoc);
return result;
}
/**
* Adds the chat text styles to the styled document passed in.
*
* @param document a <code>StyledDocument</code> value
*/
private void addChatStyles(final StyledDocument document) {
Style def = StyleContext.getDefaultStyleContext()
.getStyle(StyleContext.DEFAULT_STYLE);
Style regular = document.addStyle(ClientUISettings.STYLE_CHAT_TEXT, def);
StyleConstants.setFontFamily(regular, ClientUISettings.FONT_CHAT_TEXT);
StyleConstants.setForeground(regular, ClientUISettings.COLOR_CHAT_TEXT);
Style name = document.addStyle(ClientUISettings.STYLE_CHAT_SELF, regular);
StyleConstants.setForeground(name, ClientUISettings.COLOR_CHAT_SELF);
name = document.addStyle(ClientUISettings.STYLE_CHAT_USER, regular);
StyleConstants.setForeground(name, ClientUISettings.COLOR_CHAT_USER);
name = document.addStyle(ClientUISettings.STYLE_CHAT_CONNECTED, regular);
StyleConstants.setForeground(name, ClientUISettings.COLOR_CHAT_CONNECTED);
StyleConstants.setBold(name, true);
name = document.addStyle(ClientUISettings.STYLE_CHAT_ADMIN, name);
StyleConstants.setForeground(name, ClientUISettings.COLOR_CHAT_ADMIN);
name = document.addStyle(ClientUISettings.STYLE_CHAT_SERV, name);
StyleConstants.setForeground(name, ClientUISettings.COLOR_CHAT_SERV);
}
/**
* Adds the smilies icons into the styled document.
*
* @param doc a <code>StyledDocument</code> value
*/
private void addImageStyles(final StyledDocument doc) {
Style def = StyleContext.getDefaultStyleContext()
.getStyle(ClientUISettings.STYLE_CHAT_TEXT);
Style s = null;
BufferedImage smilie = null;
//Smile
s = doc.addStyle(ClientUISettings.CHAT_SMILE, def);
StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER);
smilie
= ImageLoader.getInstance().loadSystemImage(ClientUISettings.SMILE_ICON);
if (smilie != null) {
StyleConstants.setIcon(s, new ImageIcon(smilie));
}
//Wink
s = doc.addStyle(ClientUISettings.CHAT_WINK, def);
StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER);
smilie
= ImageLoader.getInstance().loadSystemImage(ClientUISettings.WINK_ICON);
if (smilie != null) {
StyleConstants.setIcon(s, new ImageIcon(smilie));
}
//Frown
s = doc.addStyle(ClientUISettings.CHAT_FROWN, def);
StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER);
smilie
= ImageLoader.getInstance().loadSystemImage(ClientUISettings.FROWN_ICON);
if (smilie != null) {
StyleConstants.setIcon(s, new ImageIcon(smilie));
}
//Tongue
s = doc.addStyle(ClientUISettings.CHAT_TONGUE, def);
StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER);
smilie = ImageLoader.getInstance()
.loadSystemImage(ClientUISettings.TONGUE_ICON);
if (smilie != null) {
StyleConstants.setIcon(s, new ImageIcon(smilie));
}
//Grin
s = doc.addStyle(ClientUISettings.CHAT_GRIN, def);
StyleConstants.setAlignment(s, StyleConstants.ALIGN_CENTER);
smilie
= ImageLoader.getInstance().loadSystemImage(ClientUISettings.GRIN_ICON);
if (smilie != null) {
StyleConstants.setIcon(s, new ImageIcon(smilie));
}
}
/**
* Prints the message onto the contents text pane.
*
* @param message an <code>AbstractMessage</code> value
*/
public final synchronized void
receiveMessage(final AbstractMessage message) {
StyledDocument doc = contents.getStyledDocument();
try {
if (message instanceof AbstractServerMessage) {
//Insert server name
doc.insertString(doc.getLength(),
message.getAuthor() + ": ",
doc.getStyle(ClientUISettings.STYLE_CHAT_SERV));
//Insert message text
doc.insertString(doc.getLength(),
((AbstractServerMessage) message).getServerMessage()
+ "\n",
doc.getStyle(ClientUISettings.STYLE_CHAT_TEXT));
} else if (message instanceof ChatMessage) {
ChatMessage cm = (ChatMessage) message;
StyledText[] styled = parseMessage(cm.getChatMessage());
if (cm.getAuthor().equals(Client.getInstance().getUsername())) {
//My message
doc.insertString(doc.getLength(),
cm.getAuthor() + ": ",
doc.getStyle(ClientUISettings.STYLE_CHAT_SELF));
} else {
//Somebody else's message
doc.insertString(doc.getLength(),
cm.getAuthor() + ": ",
doc.getStyle(ClientUISettings.STYLE_CHAT_USER));
}
//Insert message text
for (int i = 0; i < styled.length; i++) {
doc.insertString(doc.getLength(),
styled[i].getText(),
doc.getStyle(styled[i].getStyle()));
}
doc.insertString(doc.getLength(),
"\n",
doc.getStyle(ClientUISettings.STYLE_CHAT_TEXT));
} else if (message instanceof AdministrativeMessage) {
Style s = null;
String action = null;
if (message.getAuthor().equals(Client.getInstance().getUsername())) {
//My message
s = doc.getStyle(ClientUISettings.STYLE_CHAT_CONNECTED);
} else {
//Somebody else's message
s = doc.getStyle(ClientUISettings.STYLE_CHAT_ADMIN);
}
if (message instanceof JoinMessage) {
action = "joined";
} else if (message instanceof QuitMessage) {
action = "quit";
}
doc.insertString(doc.getLength(),
message.getAuthor() + " has " + action
+ " the session.\n",
s);
} else {
return;
}
} catch (BadLocationException ble) {
System.err.println("ChatPanel: Could not insert text into the panel...");
}
//Move the caret position to the end.
contents.setCaretPosition(doc.getLength());
}
/**
* Parses the text and returns an array of styled bits.
*
* @param text a <code>String</code> value
* @return a <code>StyledText[]</code> value
*/
private StyledText[] parseMessage(final String text) {
List list = new Vector();
String currentString = "";
Object[] ores = null;
StyledText[] result = null;
for (int i = 0; i < text.length(); i++) {
char currentChar = text.charAt(i);
if (currentChar == ':') {
if (i == (text.length() - 1)) { break; }
if (text.charAt(i + 1) == ')') {
//Got Smile Smilie...
list.add(new StyledText(currentString,
ClientUISettings.STYLE_CHAT_TEXT));
list.add(new StyledText(":)",
ClientUISettings.CHAT_SMILE));
i++;
currentString = "";
} else if (text.charAt(i + 1) == '(') {
//Got Frown Smilie...
list.add(new StyledText(currentString,
ClientUISettings.STYLE_CHAT_TEXT));
list.add(new StyledText(":(",
ClientUISettings.CHAT_FROWN));
i++;
currentString = "";
} else if (text.charAt(i + 1) == 'D') {
//Got Grin Smilie...
list.add(new StyledText(currentString,
ClientUISettings.STYLE_CHAT_TEXT));
list.add(new StyledText(":D",
ClientUISettings.CHAT_GRIN));
i++;
currentString = "";
} else if (text.charAt(i + 1) == 'p') {
//Got tongue Smilie...
list.add(new StyledText(currentString,
ClientUISettings.STYLE_CHAT_TEXT));
list.add(new StyledText(":p",
ClientUISettings.CHAT_TONGUE));
i++;
currentString = "";
} else {
currentString += ":";
}
} else if (currentChar == ';') {
if (i == (text.length() - 1)) { break; }
if (text.charAt(i + 1) == ')') {
//Got Wink Smilie...
list.add(new StyledText(currentString,
ClientUISettings.STYLE_CHAT_TEXT));
list.add(new StyledText(";)",
ClientUISettings.CHAT_WINK));
i++;
currentString = "";
} else {
currentString += ";";
}
} else {
currentString += Character.toString(currentChar);
}
}
if (!currentString.equals("")) {
list.add(new StyledText(currentString,
ClientUISettings.STYLE_CHAT_TEXT));
}
ores = list.toArray();
result = new StyledText[ores.length];
for (int j = 0; j < ores.length; j++) {
result[j] = (StyledText) ores[j];
}
return result;
}
/**
* Checks for connection. If it is present, sends the contents of
* the input field, sends them out in a chat message, and clears the
* input field.
*/
private void sendMessage() {
String text = inputField.getText();
List data = new Vector();
AbstractMessage message = null;
if (text == null || text.equals("")) {
return;
}
data.add(Client.getInstance().getUsername());
data.add(new Integer(getDocumentId()));
data.add(text);
message = MessageFactory.getInstance()
.makeMessage(MessageSettings.CHAT_TYPE, data);
Client.getInstance().sendMessage(message);
inputField.setText("");
}
/**
* Returns the id of the document with which the chat panel is associated.
*
* @return an <code>int</code> value
*/
public final int getDocumentId() {
return this.documentId;
}
/**
* Gives the document id a new value.
*
* @param value an <code>int</code> value
*/
public final void setDocumentId(final int value) {
this.documentId = value;
}
/**
* Updates the user list.
*
* @param ul an <code>UserListMessage</code> value
*/
public final void updateUserList(final UserListMessage ul) {
if (ClientUISettings.VERBOSE) {
System.out.println("ChatPanel: Updating user list with " + ul.getSize()
+ " users.");
System.out.flush();
}
clientsPanel.updateList(ul);
}
/**
* Invoked when an action occurs.
*
* @param e the event associated with the action.
*/
public final void actionPerformed(final ActionEvent e) {
sendMessage();
}
/**
* This is a little utility class that allows one to easily keep
* track of differently styled bits of text.
*/
private final class StyledText {
/**
* The text bit.
*/
private String text;
/**
* The name of the style to apply to this piece of text
*/
private String styleName;
/**
* Creates a new <code>StyledText</code> instance.
*
* @param txt a <code>String</code> value
* @param style a <code>String</code> value
*/
public StyledText(final String txt, final String style) {
text = txt;
styleName = style;
}
/**
* Returns text.
*
* @return a <code>String</code> value
*/
public String getText() {
return text;
}
/**
* Returns the style name.
*
* @return a <code>String</code> value
*/
public String getStyle() {
return styleName;
}
}
}

View File

@@ -0,0 +1,86 @@
package nettext.client.gui;
import java.awt.Dimension;
import java.awt.BorderLayout;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.DefaultListModel;
import javax.swing.ListSelectionModel;
import nettext.messaging.UserListMessage;
/**
* Class ClientListPanel: Contains a list of clients.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the ClientListPanel class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public final class ClientListPanel extends JPanel {
/**
* The list model associated with the client list.
*/
private DefaultListModel listModel;
/**
* The list box in which the list of clients will be displayed.
*/
private JList clientList;
/**
* Creates a new <code>ClientListPanel</code> instance.
*/
public ClientListPanel() {
super(new BorderLayout());
JScrollPane scroller = null;
listModel = new DefaultListModel();
clientList = new JList(listModel);
clientList
.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
clientList.setVisibleRowCount(8);
clientList.setMinimumSize(new Dimension(100, 100));
scroller = new JScrollPane(clientList);
this.add(scroller, BorderLayout.CENTER);
}
/**
* Returns an array of the names of the users that are currently selected.
*
* @return a <code>String[]</code> value
*/
public String[] getSelectedUsers() {
String[] result = null;
Object[] objs = clientList.getSelectedValues();
result = new String[objs.length];
for (int i = 0; i < objs.length; i++) {
result[i] = objs[i].toString();
}
return result;
}
/**
* Updates the list of users.
*
* @param users an <code>UserListMessage</code> value
*/
public void updateList(final UserListMessage users) {
listModel.clear();
for (int i = 0; i < users.getSize(); i++) {
listModel.addElement((String) (users.getVecList(i)));
}
}
}

View File

@@ -0,0 +1,498 @@
package nettext.client.gui;
import java.util.List;
import java.util.Vector;
import javax.swing.JOptionPane;
import javax.swing.JInternalFrame;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import java.io.File;
import nettext.document.Document;
/**
* Class ClientUI: The client ui class is the brain of the UI. It will
* take care of coordinating activity between the different UI classes
* and will also provide a facade for the other packages to interact
* with the UI through.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the ClientUI class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public final class ClientUI {
/**
* Singleton.
*/
private static ClientUI instance;
/**
* The main window, where everything is going to be displayed.
*/
private MainWindow main;
/**
* The connection dialog.
*/
private ConnectionDialog dlgConnection;
/**
* The document list frame.
*/
private MainServerFrame mainFrame;
/**
* The list of document frames.
*/
private List documentFrames;
/**
* Creates a new <code>ClientUI</code> instance.
*/
private ClientUI() {
main = new MainWindow();
dlgConnection = new ConnectionDialog(main);
mainFrame = new MainServerFrame();
documentFrames = new Vector();
//Sizes and locations
dlgConnection.pack();
main.getDesktopPane().add(mainFrame);
main.setJMenuBar(new MainMenu());
}
/**
* Part of the singleton implementation.
*
* @return a <code>ClientUI</code> value
*/
public static ClientUI getInstance() {
if (instance == null) {
instance = new ClientUI();
}
return instance;
}
/**
* This will show the main window of the front end - the one that
* will contain inside it everything else.
*/
public synchronized void startMainWindow() {
if (!isMainRunning()) {
main.setVisible(true);
}
}
/**
* Shows the connection dialog.
*/
public synchronized void showConnectionDialog() {
if (isMainRunning()) {
dlgConnection.setLocationRelativeTo(main);
dlgConnection.setVisible(true);
}
}
/**
* Shows the document list frame.
*/
public synchronized void showDocumentListFrame() {
if (isMainRunning()) {
mainFrame.setVisible(true);
}
}
/**
* Hides the document list frame.
*/
public synchronized void hideDocumentListFrame() {
mainFrame.clearAndHide();
}
/**
* Returns the document list frame.
*
* @return a <code>MainServerFrame</code> value
*/
public synchronized MainServerFrame getDocumentListFrame() {
return mainFrame;
}
/**
* Describe <code>addDocumentFrame</code> method here.
*
* @param doc a <code>Document</code> value
* @return a <code>DocumentFrame</code> value
*/
public synchronized DocumentFrame addDocumentFrame(final Document doc) {
int docId = doc.getDocumentId();
DocumentFrame result = null;
if (ClientUISettings.VERBOSE) {
System.out.println("ClientUI: Adding Document - " + doc);
System.out.flush();
}
if ((result = getDocumentFrame(docId)) == null) {
//Add the frame.
result = new DocumentFrame(doc);
documentFrames.add(result);
main.getDesktopPane().add(result);
if (ClientUISettings.VERBOSE) {
System.out.println("ClientUI: Created new document frame.");
System.out.flush();
}
} else {
//Update this frame.
result.getDocumentPanel().setDocument(doc);
if (ClientUISettings.VERBOSE) {
System.out.println("ClientUI: Updated existing document frame.");
System.out.flush();
}
}
result.setVisible(true);
result.moveToFront();
return result;
}
/**
* Describe <code>getDocumentFrame</code> method here.
*
* @param documentId an <code>int</code> value
* @return a <code>DocumentFrame</code> value
*/
public synchronized DocumentFrame getDocumentFrame(final int documentId) {
for (int i = 0; i < documentFrames.size(); i++) {
DocumentFrame frame = (DocumentFrame) documentFrames.get(i);
int id = frame.getDocumentPanel().getDocument().getDocumentId();
if (id == documentId) { return frame; }
}
return null;
}
/**
* Describe <code>showDocumentFrame</code> method here.
*
* @param documentId an <code>int</code> value
*/
public synchronized void showDocumentFrame(final int documentId) {
DocumentFrame frame = getDocumentFrame(documentId);
if (frame != null) {
frame.setVisible(true);
frame.moveToFront();
}
}
/**
* Describe <code>hideDocumentFrame</code> method here.
*
* @param documentId an <code>int</code> value
*/
public synchronized void hideDocumentFrame(final int documentId) {
for (int i = 0; i < documentFrames.size(); i++) {
DocumentFrame frame = (DocumentFrame) documentFrames.get(i);
int id = frame.getDocumentPanel().getDocument().getDocumentId();
if (id == documentId) {
//Hide frame.
frame.clearAndHide();
documentFrames.remove(i);
}
}
}
/**
* Adds the internal frame passed in to the main desktop.
*
* @param ifr a <code>JInternalFrame</code> value
*/
protected void addToMain(JInternalFrame ifr) {
main.getDesktopPane().add(ifr);
}
/**
* Returns true if the main window is currently running. No other
* windows will be allowed to show if the main window is not
* running.
*
* @return a <code>boolean</code> value
*/
public boolean isMainRunning() {
return main.isVisible();
}
////////////////////////// User message functions //////////////////////////
/**
* Displays a wanring dialog to the user.
*
* @param title a <code>String</code> value
* @param message a <code>String</code> value
*/
public void showWarning(final String title, final String message) {
if (isMainRunning()) {
showDialog(title, message, JOptionPane.WARNING_MESSAGE);
}
}
/**
* Shows an error message to the user.
*
* @param title a <code>String</code> value
* @param message a <code>String</code> value
*/
public void showError(final String title, final String message) {
if (isMainRunning()) {
showDialog(title, message, JOptionPane.ERROR_MESSAGE);
}
}
/**
* Displays an informative message to the user.
*
* @param title a <code>String</code> value
* @param message a <code>String</code> value
*/
public void showMessage(final String title, final String message) {
if (isMainRunning()) {
showDialog(title, message, JOptionPane.PLAIN_MESSAGE);
}
}
/**
* Displays a dialog with two buttons. The title and the contents of
* the dialog are passed in as the first two parameters. Tne next
* two parameters specify what labels to give to the two choice
* buttons. The function returns true if the first option was
* chosen, and false if the second option was chosen.
*
* @param title a <code>String</code> value
* @param message a <code>String</code> value
* @param yesOption a <code>String</code> value
* @param noOption a <code>String</code> value
* @return a <code>boolean</code> value
*/
public boolean showYesNoDialog(final String title,
final String message,
final String yesOption,
final String noOption) {
if (isMainRunning()) {
String[] options = {yesOption,
noOption };
int choice = JOptionPane.showOptionDialog(main,
message,
title,
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
yesOption);
if (choice == 0) {
return true;
}
return false;
}
return false;
}
/**
* Displays an input dialog and returns the string for the input the
* user provided, or null, if no input was provided.
*
* @param title a <code>String</code> value
* @param message a <code>String</code> value
* @param defaultInput a <code>String</code> value
* @return a <code>String</code> value
*/
public String showInputDialog(final String title,
final String message,
final String defaultInput) {
if (!isMainRunning()) { return null; }
String result = (String) JOptionPane
.showInputDialog(main,
message,
title,
JOptionPane.PLAIN_MESSAGE,
null,
null,
defaultInput);
if (result == null || result.length() < 1) {
return null;
}
return result;
}
/**
* A utility function for all the other showXXX functions to use.
*
* @param title a <code>String</code> value
* @param message a <code>String</code> value
* @param type an <code>int</code> value
*/
private void showDialog(final String title, final String message,
final int type) {
if (isMainRunning()) {
JOptionPane.showMessageDialog(main, message, title, type);
}
}
///////////////////////////// File Prompt Stuff /////////////////////////////
/**
* Gives the user a dialog for saving a file and allows him to
* browse the location and give the file a name. After the user
* selects the path and name of the file that he wants to save the
* session to, this value will be returned from this function.
*
* @param currentPath If this is not null, then the location that
* the browse dialog starts with will be this.
* @return a <code>String</code> value
*/
public String browseSaveFileName(final String currentPath) {
if (isMainRunning()) {
JFileChooser chooser = null;
String result = null;
int returnVal = -1;
if (currentPath == null) {
chooser = new JFileChooser();
} else {
chooser = new JFileChooser(currentPath);
}
chooser.setFileFilter(new DocumentFileFilter());
returnVal = chooser.showSaveDialog(main);
if (returnVal == JFileChooser.APPROVE_OPTION) {
result = chooser.getSelectedFile().getPath();
if (result.lastIndexOf('.') < 0
|| !result.substring(result.lastIndexOf('.') + 1).equals("xml")) {
result += ".xml";
}
return result;
} else {
return null;
}
}
return null;
}
/**
* Shows the dialog for loading a file. Will return when the user
* selects a file the name of that file and path, or null if the
* user does not make a meaningful selection or presses cancel.
*
* @param currentPath If this is not null, then the location that
* the browse dialog starts with will be this.
* @return a <code>String</code> value
*/
public String browseLoadFileName(final String currentPath) {
if (isMainRunning()) {
JFileChooser chooser = null;
String result = null;
int returnVal = -1;
if (currentPath == null) {
chooser = new JFileChooser();
} else {
chooser = new JFileChooser(currentPath);
}
chooser.setFileFilter(new DocumentFileFilter());
returnVal = chooser.showOpenDialog(main);
if (returnVal == JFileChooser.APPROVE_OPTION) {
result = chooser.getSelectedFile().getPath();
return result;
} else {
return null;
}
}
return null;
}
/**
* This class basically filters out everything that is not a
* directory or an xml file.
*/
private final class DocumentFileFilter extends FileFilter {
/**
* Creates a new <code>DocumentFileFilter</code> instance.
*/
public DocumentFileFilter() {
}
/**
* Returns true if the file passed in should be accepted and shown
* in the open/save dialog, and false if it should not be
* displayed.
*
* @param f a <code>File</code> value
* @return a <code>boolean</code> value
*/
public boolean accept(final File f) {
String name = f.getName();
String extension = null;
if (f.isDirectory()) {
return true;
}
if (name == null || name.lastIndexOf('.') < 0) {
return false;
}
extension = name.substring(name.lastIndexOf('.') + 1);
if (extension.equals("txt")
|| extension.equals("htm")
|| extension.equals("html")) {
return true;
}
return false;
}
/**
* Returns a description of this file filter.
*
* @return a <code>String</code> value
*/
public String getDescription() {
return "NetText Document Files";
}
}
}

View File

@@ -0,0 +1,468 @@
package nettext.client.gui;
import java.awt.Color;
import java.awt.Point;
import java.awt.Dimension;
/**
* Class ClientUISettings: This is a utility class that will contain
* some constants that will be shared among a few other classes in
* this and optentially some other packages.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the ClientUISettings class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public final class ClientUISettings {
/**
* Display debug output?
*/
public static final boolean VERBOSE = false;
//////////////////////////// Main Window Stuff ////////////////////////////
/**
* The title that will be given to the main window.
*/
public static final String TITLE_MAIN_WINDOW = "NetText";
/**
* The default size of the main window.
*/
public static final Dimension SIZE_MAIN_WINDOW = new Dimension(800, 600);
/////////////////////////// Document List Stuff ///////////////////////////
/**
* The title that will be given to the document list frame.
*/
public static final String TITLE_MAIN_FRAME = "Available Documents";
/**
* The default size of the document list frame.
*/
public static final Dimension SIZE_MAIN_FRAME = new Dimension(500, 400);
/**
* The default position of the document list frame.
*/
public static final Point LOCATION_MAIN_FRAME = new Point(0, 0);
////////////////////////////// Document Stuff //////////////////////////////
/**
* The title that will be given to the document list frame.
*/
public static final String TITLE_DOCUMENT = "Document: ";
/**
* The default size of the document list frame.
*/
public static final Dimension SIZE_DOCUMENT = new Dimension(500, 400);
/**
* The default position of the document list frame.
*/
public static final Point LOCATION_DOCUMENT = new Point(100, 100);
////////////////////////////// Section Stuff //////////////////////////////
/**
* The title that will be given to the section list frame.
*/
public static final String TITLE_SECTION = "Section: ";
/**
* The default size of the section list frame.
*/
public static final Dimension SIZE_SECTION = new Dimension(500, 400);
/**
* The default position of the section list frame.
*/
public static final Point LOCATION_SECTION = new Point(200, 200);
/**
* The name to give to the update button.
*/
public static final String SECTION_NAME_UPDATE = "Update";
/**
* The tooltip to give to the update button.
*/
public static final String SECTION_TOOLTIP_UPDATE = "";
/**
* The name of the icon file to load the image for the update button
* from.
*/
public static final String SECTION_ICON_UPDATE = "Update.gif";
/**
* The name to give to the save button.
*/
public static final String SECTION_NAME_SAVE = "Save";
/**
* The tooltip to give to the save button.
*/
public static final String SECTION_TOOLTIP_SAVE = "";
/**
* The name of the icon file to load the image for the save button
* from.
*/
public static final String SECTION_ICON_SAVE = "Save.gif";
/**
* The name to give to the lock button.
*/
public static final String SECTION_NAME_LOCK = "Lock";
/**
* The tooltip to give to the lock button.
*/
public static final String SECTION_TOOLTIP_LOCK = "";
/**
* The name of the icon file to load the image for the lock button
* from.
*/
public static final String SECTION_ICON_LOCK = "Lock.gif";
/**
* The name to give to the unlock button.
*/
public static final String SECTION_NAME_UNLOCK = "Unlock";
/**
* The tooltip to give to the unlock button.
*/
public static final String SECTION_TOOLTIP_UNLOCK = "";
/**
* The name of the icon file to load the image for the unlock button
* from.
*/
public static final String SECTION_ICON_UNLOCK = "Unlock.gif";
////////////////////////// Text Formatting Stuff //////////////////////////
/**
* The name to give to the bold formatting button.
*/
public static final String FORMAT_NAME_BOLD = "Bold";
/**
* The tooltip to give to the bold formatting button.
*/
public static final String FORMAT_TOOLTIP_BOLD = "";
/**
* The name of the icon file to load the image for the bold formatting
* button from.
*/
public static final String FORMAT_ICON_BOLD = "Bold.gif";
/**
* The name to give to the italic formatting button.
*/
public static final String FORMAT_NAME_ITALIC = "Italic";
/**
* The tooltip to give to the italic formatting button.
*/
public static final String FORMAT_TOOLTIP_ITALIC = "";
/**
* The name of the icon file to load the image for the italic formatting
* button from.
*/
public static final String FORMAT_ICON_ITALIC = "Italic.gif";
/**
* The name to give to the underline formatting button.
*/
public static final String FORMAT_NAME_UNDERLINE = "Underline";
/**
* The tooltip to give to the underline formatting button.
*/
public static final String FORMAT_TOOLTIP_UNDERLINE = "";
/**
* The name of the icon file to load the image for the underline
* formatting button from.
*/
public static final String FORMAT_ICON_UNDERLINE = "Underline.gif";
/**
* The name to give to the left formatting button.
*/
public static final String FORMAT_NAME_LEFT = "Align Left";
/**
* The tooltip to give to the left formatting button.
*/
public static final String FORMAT_TOOLTIP_LEFT = "";
/**
* The name of the icon file to load the image for the left
* formatting button from.
*/
public static final String FORMAT_ICON_LEFT = "AlignLeft.gif";
/**
* The name to give to the right formatting button.
*/
public static final String FORMAT_NAME_RIGHT = "Align Right";
/**
* The tooltip to give to the right formatting button.
*/
public static final String FORMAT_TOOLTIP_RIGHT = "";
/**
* The name of the icon file to load the image for the right
* formatting button from.
*/
public static final String FORMAT_ICON_RIGHT = "AlignRight.gif";
/**
* The name to give to the center formatting button.
*/
public static final String FORMAT_NAME_CENTER = "Center";
/**
* The tooltip to give to the center formatting button.
*/
public static final String FORMAT_TOOLTIP_CENTER = "";
/**
* The name of the icon file to load the image for the center
* formatting button from.
*/
public static final String FORMAT_ICON_CENTER = "AlignCenter.gif";
/**
* The name to give to the justify formatting button.
*/
public static final String FORMAT_NAME_JUSTIFY = "Justify";
/**
* The tooltip to give to the justify formatting button.
*/
public static final String FORMAT_TOOLTIP_JUSTIFY = "";
/**
* The name of the icon file to load the image for the justify
* formatting button from.
*/
public static final String FORMAT_ICON_JUSTIFY = "AlignJustify.gif";
///////////////////////////// Menu Bar Stuff /////////////////////////////
/**
* The name that will be given to the "Connect" menu item.
*/
public static final String MENU_CONNECT_NAME = "Connect";
/**
* The name that will be given to the "Disconnect" menu item.
*/
public static final String MENU_DISCONNECT_NAME = "Disconnect";
/**
* The name that will be given to the "New File" menu item.
*/
public static final String MENU_NEW_NAME = "New Document";
/**
* The name that will be given to the "Import" menu item.
*/
public static final String MENU_IMPORT_NAME = "Import Document";
/**
* The name that will be given to the "Export" menu item.
*/
public static final String MENU_EXPORT_NAME = "Export Document";
/**
* The name that will be given to the "Quit" menu item.
*/
public static final String MENU_QUIT_NAME = "Quit";
/**
* The name that will be given to the "Update" menu item.
*/
public static final String MENU_UPDATE_NAME = "Request Update";
/**
* The name that will be given to the "Save" menu item.
*/
public static final String MENU_SAVE_NAME = "Save on Server";
/**
* The name that will be given to the "Print" menu item.
*/
public static final String MENU_PRINT_NAME = "Print";
////////////////////////////// Connect Stuff //////////////////////////////
/**
* This is the title that will be given to the server connection
* dialog.
*/
public static final String TITLE_CONNECT = "Connect to Server";
/**
* In the connect dialog, the name to give to the button that allows
* the user to connect to the server.
*/
public static final String CONNECT_CONNECT_NAME = "Connect";
/**
* In the connect dialog, the name to give to the button that allows
* the user to cancel the dialog without attempting a connect.
*/
public static final String CONNECT_CANCEL_NAME = "Cancel";
/////////////////////////////// Chat Styles ///////////////////////////////
/**
* The name of the style to use for chat text.
*/
public static final String STYLE_CHAT_TEXT = "chatText";
/**
* The name of the style to use for the user's name.
*/
public static final String STYLE_CHAT_SELF = "selfName";
/**
* The name of the style to use for the names of other users.
*/
public static final String STYLE_CHAT_USER = "userName";
/**
* The name of the style to use for the server name.
*/
public static final String STYLE_CHAT_SERV = "servName";
/**
* The name of the style to use for the connected message.
*/
public static final String STYLE_CHAT_CONNECTED = "connected";
/**
* The name of the style to use for administrative messages.
*/
public static final String STYLE_CHAT_ADMIN = "administrative";
/**
* The color to use for chat text.
*/
public static final Color COLOR_CHAT_TEXT = Color.BLACK;
/**
* The color to use for the user's name.
*/
public static final Color COLOR_CHAT_SELF = Color.RED;
/**
* The color to use for the names of other users.
*/
public static final Color COLOR_CHAT_USER = Color.BLUE;
/**
* The color to use for the server name.
*/
public static final Color COLOR_CHAT_SERV = new Color(120, 0, 0);
/**
* The color in which the self join message will be shown
*/
public static final Color COLOR_CHAT_CONNECTED = new Color(20, 120, 20);
/**
* This is the color in which administrative messages will be shown.
*/
public static final Color COLOR_CHAT_ADMIN = new Color(110, 90, 20);
/**
* The font family to use for the chat text.
*/
public static final String FONT_CHAT_TEXT = "SansSerif";
/////////////////////////////// Smiley Stuff ///////////////////////////////
/**
* The name of the style to use for chat text.
*/
public static final String CHAT_SMILE = "smile";
/**
* The name of the style to use for chat text.
*/
public static final String CHAT_WINK = "wink";
/**
* The name of the style to use for chat text.
*/
public static final String CHAT_FROWN = "frown";
/**
* The name of the style to use for chat text.
*/
public static final String CHAT_TONGUE = "tongue";
/**
* The name of the style to use for chat text.
*/
public static final String CHAT_GRIN = "grin";
/**
* The name of the file that contains the icon for the text tool.
*/
public static final String SMILE_ICON = "smile.gif";
/**
* The name of the file that contains the icon for the text tool.
*/
public static final String WINK_ICON = "wink.gif";
/**
* The name of the file that contains the icon for the text tool.
*/
public static final String FROWN_ICON = "frown.gif";
/**
* The name of the file that contains the icon for the text tool.
*/
public static final String TONGUE_ICON = "tongue.gif";
/**
* The name of the file that contains the icon for the text tool.
*/
public static final String GRIN_ICON = "grin.gif";
/**
* Creates a new <code>ClientUISettings</code> instance.
*/
private ClientUISettings() { }
}

View File

@@ -0,0 +1,298 @@
package nettext.client.gui;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import nettext.client.Client;
import nettext.util.SpringUtilities;
/**
* Class ConnectionDialog: This is the dialog that will be shown when
* the user wiches to connect to a sever. It will allow the user to
* type in the host, port, and username to use when connecting to the
* server. It will then handle the connection to the server by calling
* the client. The dialog will look something like this:
*
* <PRE>
* +----------------------------------+
* | Connect to Server |
* +----------------------------------+
* | |
* | +--------------------+ |
* | Server: | | |
* | +--------------------+ |
* | +--------------------+ |
* | Port: | | |
* | +--------------------+ |
* | +--------------------+ |
* | Username: | | |
* | +--------------------+ |
* | |
* | +---------+ +--------+ |
* | | Connect | | Cancel | |
* | +---------+ +--------+ |
* | |
* +----------------------------------+
* </PRE>
*
* <PRE>
* Revision History:
* v1.0 (Feb. 02, 2004) - Created the ConnectionDialog class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 02, 2004
*/
public class ConnectionDialog extends JDialog
implements ActionListener {
/**
* The label for the server input field.
*/
private JLabel serverLabel;
/**
* The label for the port input field.
*/
private JLabel portLabel;
/**
* The label for the username input field.
*/
private JLabel usernameLabel;
/**
* The user will type the host name of the server into this input field.
*/
private JTextField serverInput;
/**
* The user will type in the port number to connect to in this
* field. It will have a default port number in it already, though.
*/
private JTextField portInput;
/**
* The user will type in the username to use when connecting to the
* server into this field.
*/
private JTextField usernameInput;
/**
* Hit this button to connect to the server.
*/
private JButton connectButton;
/**
* Hit this button to cancel.
*/
private JButton cancelButton;
/**
* Creates a new <code>ConnectionDialog</code> instance.
* @param parent a <code>Frame</code> value
*/
public ConnectionDialog(final JFrame parent) {
super(parent, true);
setTitle(ClientUISettings.TITLE_CONNECT);
//Initialize all the components:
serverLabel = new JLabel("Server: ", JLabel.TRAILING);
portLabel = new JLabel("Port: ", JLabel.TRAILING);
usernameLabel = new JLabel("Username: ", JLabel.TRAILING);
serverInput = new JTextField("localhost", 10);
portInput = new JTextField("4555", 10);
usernameInput = new JTextField(10);
usernameInput.setActionCommand(ClientUISettings.CONNECT_CONNECT_NAME);
usernameInput.addActionListener(this);
connectButton = new JButton(ClientUISettings.CONNECT_CONNECT_NAME);
cancelButton = new JButton(ClientUISettings.CONNECT_CANCEL_NAME);
connectButton.setActionCommand(ClientUISettings.CONNECT_CONNECT_NAME);
cancelButton.setActionCommand(ClientUISettings.CONNECT_CANCEL_NAME);
connectButton.addActionListener(this);
cancelButton.addActionListener(this);
//Add the components to the dialog:
JPanel contents = new JPanel(new BorderLayout());
JPanel boxes = new JPanel(new SpringLayout());
JPanel buttons = new JPanel();
//Add boxes:
boxes.add(serverLabel);
serverLabel.setLabelFor(serverInput);
boxes.add(serverInput);
boxes.add(portLabel);
portLabel.setLabelFor(portInput);
boxes.add(portInput);
boxes.add(usernameLabel);
usernameLabel.setLabelFor(usernameInput);
boxes.add(usernameInput);
//Lay out the panel.
SpringUtilities.makeCompactGrid(boxes,
3, 2, //Rows x Cols
10, 10, //x x y
5, 5); //padx x pady
//Add buttons:
buttons.add(connectButton);
buttons.add(cancelButton);
//Add it all to the content pane.
contents.add(boxes, BorderLayout.CENTER);
contents.add(buttons, BorderLayout.PAGE_END);
this.setContentPane(contents);
this.setResizable(false);
}
/**
* Returns null if the server name is not valid, and the string with
* the server name if it is valid.
*
* @return a <code>String</code> value
*/
private String validateServer() {
String value = serverInput.getText();
if (value == null) {
return null;
}
return value;
}
/**
* Returns an integer with the port number if the thing entered was
* valid, and null if it wasn't.
*
* @return an <code>Integer</code> value
*/
private Integer validatePort() {
String value = portInput.getText();
int port = -1;
if (value == null) {
return null;
}
try {
port = Integer.parseInt(value);
} catch (NumberFormatException nfe) {
//Show error message about bad port format
ClientUI.getInstance().showError("Bad Port", "The value \"" + value
+ "\" is not acceptable for a connection "
+ "port. Please enter an integer number");
return null;
}
return new Integer(port);
}
/**
* Returns the username if it was valid, and null if it wasn't. It
* is not allowed to have colons in the username.
*
* @return a <code>String</code> value
*/
private String validateUsername() {
String value = usernameInput.getText();
/*
* removed for pmd
* int index = 0;
*/
if (value == null) {
return null;
}
return value;
}
/**
* Will be called when the connect button is clicked.
*/
private void connect() {
String host = validateServer();
Integer port = validatePort();
String username = validateUsername();
boolean result = false;
if (host == null
|| port == null
|| username == null) {
//Not enough data...
return;
}
result = Client.getInstance().connectToServer(host,
port.intValue(),
username);
if (!result) {
//Show error message about how we couldn't connect to the server.
ClientUI.getInstance().showError("Connection Failed",
"Could not connect to the server: "
+ username + "@" + host
+ ":" + port.toString());
} else {
//Connected successfully.
clearAndHide();
}
}
/**
* Will be called when the cancel button is clicked.
*/
private void cancel() {
clearAndHide();
}
/**
* Invoked when an action occurs.
*
* @param e the event associated with the action.
*/
public final void actionPerformed(final ActionEvent e) {
String actionCommand = e.getActionCommand();
if (actionCommand.equals(ClientUISettings.CONNECT_CONNECT_NAME)) {
connect();
} else if (actionCommand.equals(ClientUISettings.CONNECT_CANCEL_NAME)) {
cancel();
} else {
System.out.println("ConnectionDialog::actionPerformed - unknown "
+ "command - " + actionCommand);
}
}
/** This method clears the dialog and hides it. */
public final void clearAndHide() {
/*
serverInput.setText(null);
portInput.setText(null);
usernameInput.setText(null);
*/
setVisible(false);
}
}

View File

@@ -0,0 +1,374 @@
package nettext.client.gui;
import java.util.List;
import java.util.Vector;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
import javax.swing.JSplitPane;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameAdapter;
import nettext.client.Client;
import nettext.util.UIUtilities;
import nettext.document.Document;
import nettext.document.DocumentSection;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
/**
* Class DocumentFrame: will be shown whenever we receive a document
* update message if necessary. This guy will display a document and
* the chat room associated with it. It will also display the list of
* sections available for the document and allow to create new
* sections.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 21, 2004) - Created the DocumentFrame class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 21, 2004
*/
public class DocumentFrame extends JInternalFrame {
/**
* The chat panel.
*/
private ChatPanel chat;
/**
* The document panel.
*/
private DocumentPanel docPanel;
/**
* The panel for the list of sections.
*/
private SectionListPane secPanel;
/**
* The list of section frames associated with this document.
*/
private List sectionFrames;
/**
* Creates a new <code>DocumentFrame</code> instance.
* @param doc The document that will be displayed in this panel.
*/
public DocumentFrame(final Document doc) {
super(ClientUISettings.TITLE_DOCUMENT + doc.getDocumentName(), //Title
true, //Resizable
true, //Closable
true, //Maximizable
true); //Iconifiable
sectionFrames = new Vector();
this.setContentPane(createContentPane(doc));
this.setSize(ClientUISettings.SIZE_DOCUMENT);
this.setLocation(ClientUISettings.LOCATION_DOCUMENT);
//Define custom behaviour for closing:
this.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
this.addInternalFrameListener(new InternalFrameAdapter() {
public void internalFrameClosing(InternalFrameEvent e) {
int docId
= getDocumentPanel().getDocument().getDocumentId();
//Close all of the section frames first:
while (sectionFrames.size() > 0) {
hideSectionFrame(((SectionFrame) sectionFrames.get(0))
.getDocumentSection().getSectionId());
}
ClientUI.getInstance().hideDocumentFrame(docId);
}
});
this.setJMenuBar(createMenuBar());
}
/**
* Creates a menu bar.
*
* @return a <code>JMenuBar</code> value
*/
private JMenuBar createMenuBar() {
JMenuBar r = new JMenuBar();
JMenu result = new JMenu("Document");
JMenuItem tempItem = null;
ActionListener l = null;
//Update
l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
List data = new Vector();
data.add(Client.getInstance().getUsername());
data.add(new Integer(getDocumentPanel()
.getDocument().getDocumentId()));
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.UPDATE_TYPE,
data));
}
};
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_UPDATE_NAME, KeyEvent.VK_R, l);
result.add(tempItem);
//Save
l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
List data = new Vector();
data.add(getDocumentPanel().getDocument());
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.DOC_TRANSFER_TYPE,
data));
}
};
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_SAVE_NAME, KeyEvent.VK_S, l);
result.add(tempItem);
result.addSeparator();
//Export
l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Client.getInstance().exportDocument(getDocumentPanel()
.getDocument());
}
};
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_EXPORT_NAME, KeyEvent.VK_E, l);
result.add(tempItem);
result.addSeparator();
//Print
l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
};
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_PRINT_NAME, KeyEvent.VK_P, l);
result.add(tempItem);
r.add(result);
return r;
}
/**
* Creates the content pane.
*
* @param doc a <code>Document</code> value
* @return a <code>JPanel</code> value
*/
private JPanel createContentPane(final Document doc) {
JPanel result = new JPanel(new BorderLayout());
JSplitPane split = null;
chat = new ChatPanel(doc.getDocumentId());
split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
createDocumentPanel(doc),
chat);
split.setOneTouchExpandable(true);
result.add(split, BorderLayout.CENTER);
return result;
}
/**
* Creates the document panel.
*
* @param doc a <code>Document</code> value
* @return a <code>JPanel</code> value
*/
private JPanel createDocumentPanel(final Document doc) {
JPanel panel = new JPanel(/*new BorderLayout()*/);
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
docPanel = new DocumentPanel(doc);
secPanel = new SectionListPane(doc);
panel.add(secPanel); //, BorderLayout.WEST);
panel.add(docPanel); //, BorderLayout.CENTER);
return panel;
}
/**
* Adds and shows a section frame for the section passed in.
*
* @param sec a <code>DocumentSection</code> value
* @return a <code>SectionFrame</code> value
*/
public SectionFrame addSectionFrame(DocumentSection sec) {
int secId = sec.getSectionId();
SectionFrame result = null;
if (ClientUISettings.VERBOSE) {
System.out.println("DocumentFrame: Adding Section - " + sec);
System.out.flush();
}
if ((result = getSectionFrame(secId)) == null) {
//Add the frame.
result = new SectionFrame(sec);
sectionFrames.add(result);
ClientUI.getInstance().addToMain(result);
if (ClientUISettings.VERBOSE) {
System.out.println("ClientUI: Created new section frame.");
System.out.flush();
}
} else {
//FIXME: Update this frame.
//result.getSectionPanel().setSection(doc);
if (ClientUISettings.VERBOSE) {
System.out.println("ClientUI: Updated existing section frame.");
System.out.flush();
}
}
result.setVisible(true);
result.moveToFront();
return result;
}
/**
* Returns the section frame for the section with the id passed in,
* or null if such a frame does not exist.
*
* @param sectionId a <code>DocumentSection</code> value
* @return a <code>SectionFrame</code> value
*/
public SectionFrame getSectionFrame(int sectionId) {
for (int i = 0; i < sectionFrames.size(); i++) {
SectionFrame frame = (SectionFrame) sectionFrames.get(i);
int id = frame.getDocumentSection().getSectionId();
if (id == sectionId) { return frame; }
}
return null;
}
/**
* Describe <code>showSectionFrame</code> method here.
*
* @param sectionId an <code>int</code> value
*/
public synchronized void showSectionFrame(final int sectionId) {
SectionFrame frame = getSectionFrame(sectionId);
if (frame != null) {
frame.setVisible(true);
frame.moveToFront();
}
}
/**
* Hides and disposes of the frame for the section id passed in.
*
* @param sectionId an <code>int</code> value
*/
public void hideSectionFrame(int sectionId) {
for (int i = 0; i < sectionFrames.size(); i++) {
SectionFrame frame = (SectionFrame) sectionFrames.get(i);
int id = frame.getDocumentSection().getSectionId();
if (id == sectionId) {
//Hide frame.
frame.clearAndHide();
sectionFrames.remove(i);
}
}
}
/**
* Returns the chat panel.
*
* @return a <code>ChatPanel</code> value
*/
public ChatPanel getChatPanel() {
return chat;
}
/**
* Returns the DocumentPanel.
*
* @return a <code>DocumentPanel</code> value
*/
public DocumentPanel getDocumentPanel() {
return docPanel;
}
/**
* Returns the SectionListPane.
*
* @return a <code>SectionListPane</code> value
*/
public SectionListPane getSectionListPane() {
return secPanel;
}
/**
* Describe <code>setVisible</code> method here.
*
* @param value a <code>boolean</code> value
*/
public void setVisible(final boolean value) {
super.setVisible(value);
}
/**
* Clears out the contents and hides the frame.
*/
public void clearAndHide() {
int docId = this.getDocumentPanel().getDocument().getDocumentId();
setVisible(false);
List data = null;
//FIXME: If the document has been updated, ask the user if they
//want to send the updates to the server. If so, send the updated
//document to the server.
//Send out a message that we are done viewing.
data = new Vector();
data.add(Client.getInstance().getUsername());
data.add(new Integer(docId));
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.UNVIEW_SECT_TYPE, data));
//Done
this.dispose();
}
}

View File

@@ -0,0 +1,171 @@
package nettext.client.gui;
import java.util.List;
import java.util.Vector;
import java.awt.Component;
import java.awt.BorderLayout;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import nettext.document.Document;
import nettext.messaging.DocumentListMessage;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
import nettext.client.Client;
/**
* Class DocumentListPanel: will contain the list of documents
* available from the server and will allow the user to select one of
* the documents, upon which action, the document window will be
* opened for that particular document.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the DocumentListPanel class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 20, 2004
*/
public class DocumentListPanel extends JPanel
implements ListSelectionListener {
/**
* The list model associated with the document list.
*/
private DefaultListModel listModel;
/**
* The list box in which the list of documents will be displayed.
*/
private JList documentList;
/**
* Creates a new <code>DocumentListPanel</code> instance.
*/
public DocumentListPanel() {
super(new BorderLayout());
JScrollPane scroller = null;
listModel = new DefaultListModel();
documentList = new JList(listModel);
documentList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
documentList.addListSelectionListener(this);
documentList.setVisibleRowCount(8);
documentList.setCellRenderer(new DocumentItemRenderer());
scroller = new JScrollPane(documentList);
this.add(scroller, BorderLayout.CENTER);
}
/**
* Updates the list of documents.
*
* @param documents an <code>UserListMessage</code> value
*/
public void updateList(final DocumentListMessage documents) {
listModel.clear();
for (int i = 0; i < documents.getSize(); i++) {
listModel.addElement(documents.getVecList(i));
}
}
/**
* Invoked when an action occurs.
*
* @param e the event associated with the action.
*/
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
if (documentList.getSelectedIndex() == -1) {
//No selection
return;
} else {
//Selection
//Get the id of the document selected:
int id = ((Document) (documentList.getSelectedValue())).getDocumentId();
//See if a document panel for this already exists:
DocumentFrame f = ClientUI.getInstance().getDocumentFrame(id);
if (f == null) {
//Tell the client to send out a request for the document.
List data = new Vector();
data.add(Client.getInstance().getUsername());
data.add(new Integer(id));
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.VIEW_SECT_TYPE, data));
} else {
//Bring the frame to front:
f.moveToFront();
try {
f.setSelected(true);
} catch (Exception exc) {
System.out.println("Screw You, JAVA!");
}
}
}
}
}
/**
* This class will be used to render items in the list of documents.
*/
private final class DocumentItemRenderer implements ListCellRenderer {
/**
* Creates a new <code>DocumentItemRenderer</code> instance.
*/
public DocumentItemRenderer() { }
/**
* Return a component that has been configured to display the
* specified value. That component's paint method is then called
* to "render" the cell. If it is necessary to compute the
* dimensions of a list because the list cells do not have a fixed
* size, this method is called to generate a component on which
* getPreferredSize can be invoked.
*
* @param list The JList we're painting.
* @param value The value returned by list.getModel().getElementAt(index).
* @param index The cell's index.
* @param isSelected True if the specified cell was selected.
* @param cellHasFocus True if the specified cell has the focus.
* @return A component whose paint() method will render the
* specified value.
*/
public Component getListCellRendererComponent(final JList list,
final Object value,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
String color = "";
if (isSelected) {
color = "#9400D3";
} else {
color = "blue";
}
return new JLabel("<html><font color=\"" + color + "\"><b><u>"
+ value.toString()
+ "</u></b></font>");
}
}
}

View File

@@ -0,0 +1,139 @@
package nettext.client.gui;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import nettext.document.Document;
import nettext.document.DocumentSection;
import nettext.document.SectionList;
import nettext.client.Client;
/**
* Class DocumentPanel: The document panel will show a fully rendered
* document.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 22, 2004) - Created the DocumentPanel class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 22, 2004
*/
public final class DocumentPanel extends JPanel {
/**
* The document to be displayed.
*/
private Document doc;
/**
* The pane in which the document will be displayed.
*/
private JEditorPane textPane;
/**
* Creates a new <code>DocumentPanel</code> instance.
* @param d a <code>Document</code> value
*/
public DocumentPanel(final Document d) {
super(new BorderLayout());
JScrollPane scroller = null;
JEditorPane t = createTextPane();
scroller = new JScrollPane(t);
this.add(scroller, BorderLayout.CENTER);
doc = d;
updateDocument();
}
/**
* Creates the text editor pane to display the document.
*
* @return a <code>JEditorPane</code> value
*/
private JEditorPane createTextPane() {
JEditorPane result = new JEditorPane("text/html", "");
textPane = result;
result.setEditable(false);
return result;
}
/**
* Returns the document.
*
* @return a <code>Document</code> value
*/
public Document getDocument() {
return doc;
}
/**
* Sets the new document to render.
* @param d document
*/
public void setDocument(final Document d) {
for (int i = 0; i < doc.getSections().size(); i++) {
if (doc.getSections().getSectionAt(i).isSectionLocked()
&& doc.getSections().getSectionAt(i).getUserName()
.equals(Client.getInstance().getUsername())) {
System.out.println("DocumentPanel: Skipping section - " + i);
DocumentSection s = doc.getSections().getSectionAt(i);
d.getSections().removeSectionAt(i);
d.getSections().insert(s, i);
}
}
doc = d;
updateDocument();
}
/**
* Rerenders the document.
*/
public void updateDocument() {
String text = "<html>";
if (doc == null || !doc.isDocumentLoaded()) {
//Nothing to render:
text += "<font color=\"red\"><b>";
text += "Document not loaded...";
text += "</b></font>";
} else {
SectionList sl = doc.getSections();
//Render document name:
text += "<H2>";
text += doc.getDocumentName();
text += "</H2><HR width=\"80%\">";
for (int i = 0; i < sl.size(); i++) {
DocumentSection s = sl.getSectionAt(i);
//Render section title:
text += "<BR><H3>";
text += s.getSectionName();
text += "</H3>";
//Render section text:
text += s.getSectionContents();
}
}
//Set text:
textPane.setText(text);
}
}

View File

@@ -0,0 +1,98 @@
package nettext.client.gui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import nettext.client.Client;
import nettext.util.UIUtilities;
/**
* Class <code>MainMenu</code> contains the menu bar for the program.
*
* @author <a href="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</a>
* @version 1.0
*/
public class MainMenu extends JMenuBar implements ActionListener {
/**
* Creates a new <code>MainMenu</code> instance.
*/
public MainMenu() {
this.add(makeFileMenu());
}
/**
* Makes the file menu.
*
* @return a <code>JMenu</code> value
*/
private JMenu makeFileMenu() {
JMenu result = new JMenu("File");
JMenuItem tempItem = null;
//Connect
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_CONNECT_NAME, KeyEvent.VK_C, this);
result.add(tempItem);
//Disconnect
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_DISCONNECT_NAME,
KeyEvent.VK_D, this);
result.add(tempItem);
//Separator
result.addSeparator();
//Quit
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_QUIT_NAME, KeyEvent.VK_Q, this);
result.add(tempItem);
return result;
}
/**
* Invoked when an action occurs.
*
* @param e the event associated with the action.
*/
public final void actionPerformed(final ActionEvent e) {
String action = e.getActionCommand();
if (ClientUISettings.MENU_CONNECT_NAME.equals(action)) {
if (!Client.getInstance().isConnected()) {
ClientUI.getInstance().showConnectionDialog();
} else {
ClientUI.getInstance()
.showMessage("Already Connected",
"A connection to a server is already present. If you "
+ "wish to connect to another server, please disconne"
+ "ct from this one first.");
}
} else if (ClientUISettings.MENU_DISCONNECT_NAME.equals(action)) {
if (Client.getInstance().isConnected()) {
Client.getInstance().disconnectFromServer(true);
} else {
ClientUI.getInstance()
.showMessage("No Connection",
"No connection is currently present to a server.");
}
} else if (ClientUISettings.MENU_QUIT_NAME.equals(action)) {
//Quit program
Client.getInstance().shutDown();
} else {
System.out.println("MainMenu: Unknown menu item - " + action);
return;
}
}
}

View File

@@ -0,0 +1,113 @@
package nettext.client.gui;
import java.awt.Dimension;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JInternalFrame;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameAdapter;
/**
* Class MainServerFrame: will be shown when the user connects to the
* server. It will contain the list of documents available from the
* server and the globsl chat panel.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 21, 2004) - Created the MainServerFrame class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 21, 2004
*/
public class MainServerFrame extends JInternalFrame {
/**
* The chat panel.
*/
private ChatPanel chat;
/**
* The document list panel.
*/
private DocumentListPanel docList;
/**
* Creates a new <code>MainServerFrame</code> instance.
*/
public MainServerFrame() {
super(ClientUISettings.TITLE_MAIN_FRAME, //Title
true, //Resizable
false, //Closable
true, //Maximizable
true); //Iconifiable
this.setContentPane(createContentPane());
this.setSize(ClientUISettings.SIZE_MAIN_FRAME);
this.setLocation(ClientUISettings.LOCATION_MAIN_FRAME);
//Define custom behaviour for closing:
this.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
this.addInternalFrameListener(new InternalFrameAdapter() {
public void internalFrameClosing(InternalFrameEvent e) {
clearAndHide();
}
});
this.setJMenuBar(new ServerMenu());
}
/**
* Creates the content pane.
*
* @return a <code>JPanel</code> value
*/
private JPanel createContentPane() {
JPanel result = new JPanel(new BorderLayout());
JSplitPane split = null;
docList = new DocumentListPanel();
chat = new ChatPanel(0);
docList.setMinimumSize(new Dimension(100, 100));
chat.setMinimumSize(new Dimension(100, 100));
split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, docList, chat);
split.setOneTouchExpandable(true);
result.add(split, BorderLayout.CENTER);
return result;
}
/**
* Returns the chat panel.
*
* @return a <code>ChatPanel</code> value
*/
public ChatPanel getChatPanel() {
return chat;
}
/**
* Returns the DocumentListPanel.
*
* @return a <code>DocumentListPanel</code> value
*/
public DocumentListPanel getDocumentListPanel() {
return docList;
}
/**
* Clears out the contents and hides the frame.
*/
public void clearAndHide() {
//FIXME: Implement it so the contents of the chat panel and the
//document list are cleared.
setVisible(false);
}
}

View File

@@ -0,0 +1,75 @@
package nettext.client.gui;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import javax.swing.JFrame;
import javax.swing.JDesktopPane;
import nettext.client.Client;
/**
* Class MainWindow: The main window is just what the name implies. It
* is the container window for all of the other front end frames.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 02, 2004) - Created the MainWindow class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 02, 2004
*/
public class MainWindow extends JFrame {
/**
* This is the special desktop pane that will be the content pane
* for this window. It will allow us to minimize the internal
* frames, which will make it all pretty and amazing.
*/
private JDesktopPane desktop;
/**
* Creates a new <code>MainWindow</code> instance.
*/
public MainWindow() {
super(ClientUISettings.TITLE_MAIN_WINDOW);
//Put the window smack in the middle of the screen, and give it
//dimensions as defined by the settings:
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int xOffset = screenSize.width - ClientUISettings.SIZE_MAIN_WINDOW.width;
int yOffset = screenSize.height - ClientUISettings.SIZE_MAIN_WINDOW.height;
this.setBounds(xOffset / 2, yOffset / 2,
screenSize.width - xOffset,
screenSize.height - yOffset);
//Create the desktop pane:
desktop = new JDesktopPane();
this.setContentPane(desktop);
//Make dragging smooth but ugly:
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
//Define custom behaviour for closing:
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
Client.getInstance().shutDown();
}
});
}
/**
* Returns the desktop pane used in this frame.
*
* @return a <code>JDesktopPane</code> value
*/
public final JDesktopPane getDesktopPane() {
return desktop;
}
}

View File

@@ -0,0 +1,744 @@
package nettext.client.gui;
import java.util.Vector;
import java.util.Map;
import java.util.HashMap;
import java.awt.Color;
import java.awt.Insets;
import java.awt.Window;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentAdapter;
import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JTextPane;
import javax.swing.JScrollPane;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JToolBar;
import javax.swing.BorderFactory;
import javax.swing.JColorChooser;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.JTextComponent;
import javax.swing.text.StyleConstants;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.InputMap;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.DefaultEditorKit;
import java.awt.Event;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.html.HTMLEditorKit;
import nettext.document.Document;
import nettext.document.DocumentSection;
import nettext.util.UIUtilities;
/**
* Class SectionEditorPane: will contain a panel that will allow the
* user to edit the contents of a section.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 24, 2004) - Created the SectionEditorPane class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 24, 2004
*/
public final class SectionEditorPane extends JPanel implements ActionListener {
/**
* This is a little panel that will indicate the currently chosen color.
*/
private JButton colorIndicator;
/**
* This is the text pane, where the editing will be done.
*/
private JTextPane textPane;
/**
* This document will contain the actual text.
*/
private DefaultStyledDocument doc;
/**
* The editor kit to use.
*/
private HTMLEditorKit kit;
/**
* The hash map of actions.
*/
private Map actions;
/**
* The toolbar with stuff.
*/
private JToolBar tools;
/**
* The combo box for the font face selection.
*/
private JComboBox fontFaceCombo;
/**
* Contains the name of the current font face.
*/
private String currentFontFace;
/**
* The combo box to store the font size settings.
*/
private JComboBox fontSizeCombo;
/**
* The currently selected font size.
*/
private int currentFontSize;
/**
* Contains the currently selected color.
*/
private Color currentColor;
/**
* The id of the document being edited.
*/
private int currentDocId;
/**
* The id of the section being edited.
*/
private int currentSecId;
/**
* Creates a new <code>SectionEditorPane</code> instance.
*/
public SectionEditorPane() {
super(new BorderLayout());
currentColor = Color.black;
JScrollPane scrollPane = new JScrollPane(createTextPane());
scrollPane.setPreferredSize(new Dimension(200, 200));
add(createToolBar(), BorderLayout.PAGE_START);
// this.add(createToolPane(), BorderLayout.NORTH);
this.add(scrollPane, BorderLayout.CENTER);
}
/**
* Creates and configures the text pane.
*
* @return a <code>JTextPane</code> value
*/
private JTextPane createTextPane() {
textPane = new JTextPane();
textPane.setCaretPosition(0);
textPane.setMargin(new Insets(5, 5, 5, 5));
kit = new HTMLEditorKit();
doc = (DefaultStyledDocument) kit.createDefaultDocument();
textPane.setEditorKit(kit);
textPane.setStyledDocument(doc);
textPane.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
updateDocumentFrame();
}
});
createActionTable(textPane);
return textPane;
}
/**
*This updates document Frame.
*
*/
/**
* Updates the parent.
*/
protected void updateDocumentFrame() {
DocumentFrame df = ClientUI.getInstance()
.getDocumentFrame(currentDocId);
if (df == null) { return; }
Document document = df.getDocumentPanel().getDocument();
DocumentSection s = document.getSections().getSection(currentSecId);
if (s == null) { return; }
s.setSectionContents(getHTML());
s.updateTimeStamp();
document.updateDocument();
df.getDocumentPanel().setDocument(document);
df.getDocumentPanel().updateDocument();
}
/**
* Creates the toolbar.
*
* @return a <code>JToolBar</code> value
*/
private JToolBar createToolBar() {
JButton currentButton = null;
Action action = null;
tools = new JToolBar("Font Tools");
tools.setRollover(true);
//Color
tools.add(makeColorChooser());
//Separator
tools.addSeparator();
//Font Face
tools.add(makeFontNameBox());
//Font Size
tools.add(makeFontSizeBox());
//Separator
tools.addSeparator();
//Bold
action = new StyledEditorKit.BoldAction();
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_BOLD);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_BOLD,
ClientUISettings.FORMAT_TOOLTIP_BOLD,
ClientUISettings.FORMAT_ICON_BOLD,
action,
this);
tools.add(currentButton);
//Italic
action = new StyledEditorKit.ItalicAction();
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_ITALIC);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_ITALIC,
ClientUISettings.FORMAT_TOOLTIP_ITALIC,
ClientUISettings.FORMAT_ICON_ITALIC,
action,
this);
tools.add(currentButton);
//Underline
action = new StyledEditorKit.UnderlineAction();
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_UNDERLINE);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_UNDERLINE,
ClientUISettings.FORMAT_TOOLTIP_UNDERLINE,
ClientUISettings.FORMAT_ICON_UNDERLINE,
action,
this);
tools.add(currentButton);
//Separator:
tools.addSeparator();
//Left
action = new StyledEditorKit.AlignmentAction("Left",
StyleConstants.ALIGN_LEFT);
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_LEFT);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_LEFT,
ClientUISettings.FORMAT_TOOLTIP_LEFT,
ClientUISettings.FORMAT_ICON_LEFT,
action,
this);
tools.add(currentButton);
//Center
action = new StyledEditorKit.AlignmentAction("Center",
StyleConstants.ALIGN_CENTER);
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_CENTER);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_CENTER,
ClientUISettings.FORMAT_TOOLTIP_CENTER,
ClientUISettings.FORMAT_ICON_CENTER,
action,
this);
tools.add(currentButton);
//Right
action = new StyledEditorKit.AlignmentAction("Right",
StyleConstants.ALIGN_RIGHT);
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_RIGHT);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_RIGHT,
ClientUISettings.FORMAT_TOOLTIP_RIGHT,
ClientUISettings.FORMAT_ICON_RIGHT,
action,
this);
tools.add(currentButton);
//Justify
action
= new StyledEditorKit.AlignmentAction("Justify",
StyleConstants.ALIGN_JUSTIFIED);
action.putValue(Action.NAME, ClientUISettings.FORMAT_NAME_JUSTIFY);
currentButton = UIUtilities.getInstance()
.makeIconButton(ClientUISettings.FORMAT_NAME_JUSTIFY,
ClientUISettings.FORMAT_TOOLTIP_JUSTIFY,
ClientUISettings.FORMAT_ICON_JUSTIFY,
action,
this);
tools.add(currentButton);
//Separator:
tools.addSeparator();
return tools;
}
/**
* Makes the panel that contains the font face and size selection
* combo boxes.
*
* @return a <code>JPanel</code> value
*/
private JPanel makeFontSelectionPanel() {
JPanel result = new JPanel();
result.setLayout(new BoxLayout(result, BoxLayout.X_AXIS));
result.add(makeFontNameBox());
result.add(makeFontSizeBox());
return result;
}
/**
* Makes a combo box that allows you to select the font type.
*
* @return a <code>JComboBox</code> value
*/
private JComboBox makeFontNameBox() {
String[] allFamilies = GraphicsEnvironment
.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
fontFaceCombo = new JComboBox(allFamilies);
fontFaceCombo.setMaximumSize(fontFaceCombo.getPreferredSize());
fontFaceCombo.setActionCommand("font_name_select");
fontFaceCombo.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
currentFontFace = fontFaceCombo.getSelectedItem().toString();
MutableAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setFontFamily(attr, currentFontFace);
setAttributeSet(attr);
textPane.grabFocus();
updateDocumentFrame();
}
});
return fontFaceCombo;
}
/**
* Returns a combo box filled with some sizes for the fonts.
*
* @return a <code>JComboBox</code> value
*/
private JComboBox makeFontSizeBox() {
Vector sizes = new Vector();
sizes.add(new Integer(8));
sizes.add(new Integer(9));
sizes.add(new Integer(10));
sizes.add(new Integer(11));
sizes.add(new Integer(12));
sizes.add(new Integer(14));
sizes.add(new Integer(16));
sizes.add(new Integer(18));
sizes.add(new Integer(20));
sizes.add(new Integer(22));
sizes.add(new Integer(24));
sizes.add(new Integer(26));
sizes.add(new Integer(28));
sizes.add(new Integer(36));
sizes.add(new Integer(48));
sizes.add(new Integer(72));
fontSizeCombo = new JComboBox(sizes);
fontSizeCombo.setMaximumSize(fontSizeCombo.getPreferredSize());
fontSizeCombo.setEditable(true);
fontSizeCombo.setSelectedIndex(4);
fontSizeCombo.setActionCommand("font_size_select");
fontSizeCombo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int fontSize = 12;
try {
fontSize = Integer.parseInt(fontSizeCombo.
getSelectedItem().toString());
} catch (NumberFormatException ex) { return; }
currentFontSize = fontSize;
MutableAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setFontSize(attr, currentFontSize);
setAttributeSet(attr);
textPane.grabFocus();
updateDocumentFrame();
}
});
return fontSizeCombo;
}
/**
* Returns a panel that contains a color chooser.
*
* @return a <code>JPanel</code> value
*/
private JPanel makeColorChooser() {
JPanel result = new JPanel();
JPanel container = new JPanel(new BorderLayout());
colorIndicator = new JButton(" ");
colorIndicator.setBackground(currentColor);
colorIndicator.setActionCommand("color_chooser");
colorIndicator.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
//Show the color chooser:
Color newColor = showColorChooser();
if (newColor != null) {
//The user has actually picked a color
currentColor = newColor;
MutableAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, currentColor);
setAttributeSet(attr);
colorIndicator.setBackground(currentColor);
textPane.grabFocus();
updateDocumentFrame();
}
}
});
colorIndicator.setBorderPainted(false);
colorIndicator.setFocusPainted(false);
container.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createRaisedBevelBorder(),
BorderFactory.createLoweredBevelBorder()));
container.add(colorIndicator, BorderLayout.CENTER);
result.add(container);
return result;
}
/**
* Adds a few key bindings for text navigation, and editing stuff.
*/
protected void addBindings() {
InputMap inputMap = textPane.getInputMap();
//Ctrl-b to go backward one character
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK);
inputMap.put(key, DefaultEditorKit.backwardAction);
//Ctrl-f to go forward one character
key = KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK);
inputMap.put(key, DefaultEditorKit.forwardAction);
//Ctrl-p to go up one line
key = KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK);
inputMap.put(key, DefaultEditorKit.upAction);
//Ctrl-n to go down one line
key = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK);
inputMap.put(key, DefaultEditorKit.downAction);
}
/**
* Creates the action table for the panel.
*
* @param textComponent a <code>JTextComponent</code> value
*/
private void createActionTable(JTextComponent textComponent) {
actions = new HashMap();
Action[] actionsArray = textComponent.getActions();
for (int i = 0; i < actionsArray.length; i++) {
Action a = actionsArray[i];
actions.put(a.getValue(Action.NAME), a);
if (ClientUISettings.VERBOSE) {
System.out.println("Action - " + a.getValue(Action.NAME));
System.out.flush();
}
}
}
/**
* Returns the action with the specified name.
*
* @param name a <code>String</code> value
* @return an <code>Action</code> value
*/
private Action getActionByName(String name) {
return (Action) (actions.get(name));
}
/**
* Invoked when an action occurs.
*
* @param e the event associated with the action.
*/
public void actionPerformed(final ActionEvent e) {
String action = e.getActionCommand();
if (ClientUISettings.FORMAT_NAME_BOLD.equals(action)) {
textPane.requestFocus();
} else if (ClientUISettings.FORMAT_NAME_ITALIC.equals(action)) {
textPane.requestFocus();
} else if (ClientUISettings.FORMAT_NAME_UNDERLINE.equals(action)) {
textPane.requestFocus();
} else if (ClientUISettings.FORMAT_NAME_LEFT.equals(action)) {
textPane.requestFocus();
} else if (ClientUISettings.FORMAT_NAME_RIGHT.equals(action)) {
textPane.requestFocus();
} else if (ClientUISettings.FORMAT_NAME_CENTER.equals(action)) {
textPane.requestFocus();
} else if (ClientUISettings.FORMAT_NAME_JUSTIFY.equals(action)) {
textPane.requestFocus();
} else {
System.out.println("SectionEditorPane: Unknown Action Performed - "
+ action);
System.out.flush();
}
updateDocumentFrame();
if (ClientUISettings.VERBOSE) {
try {
// System.out.println(doc.getText(0, doc.getLength()));
System.out.println(textPane.getText());
System.out.flush();
} catch (Exception ex) { System.out.println("exception\n"); }
}
}
/**
*sets the attribute set.
*@param attr attribute
*/
protected void setAttributeSet(AttributeSet attr) {
int xStart = textPane.getSelectionStart();
int xFinish = textPane.getSelectionEnd();
if (xStart != xFinish) {
doc.setCharacterAttributes(xStart, xFinish - xStart,
attr, false);
}
}
/**
* Shows the color chooser and returns the color that the user selected.
*
* @return a <code>Color</code> value
*/
protected Color showColorChooser() {
JColorChooser pane = new JColorChooser(currentColor);
pane.setPreviewPanel(new JPanel());
ColorTracker ok = new ColorTracker(pane);
JDialog dialog = JColorChooser.createDialog(this,
"Choose text color",
true,
pane,
ok,
null);
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
Window w = e.getWindow();
w.hide();
}
});
dialog.addComponentListener(new ComponentAdapter() {
public void componentHidden(ComponentEvent e) {
Window w = (Window) e.getComponent();
w.dispose();
}
});
dialog.show(); // blocks until user brings dialog down...
return ok.getColor();
}
/**
* Describe <code>setEnabled</code> method here.
*
* @param v a <code>boolean</code> value
*/
public void setEnabled(final boolean v) {
textPane.setEditable(v);
}
/**
* Sets the contents of the text pane to the section.
*
* @param s a <code>DocumentSection</code> value
*/
public void setSection(final DocumentSection s) {
currentDocId = s.getDocumentId();
currentSecId = s.getSectionId();
String temp = s.getSectionContents().trim();
if (!temp.startsWith("<p>")) {
temp = "<p>" + temp + "</p>";
}
String text = "<html>";
text += "<head></head><body>";
text += temp;
text += "</body></html>";
textPane.setText(text);
}
/**
* Returns the stuff the user has got so far.
*
* @return a <code>String</code> value
*/
public String getHTML() {
String text = textPane.getText();
//Leave only the contents of the section in.
text = text.replaceAll("<html>", "");
text = text.replaceAll("</html>", "");
text = text.replaceAll("<head>", "");
text = text.replaceAll("</head>", "");
text = text.replaceAll("<body>", "");
text = text.replaceAll("</body>", "");
text = nettext.util.ContentProcessor.getInstance().stripNewlines(text);
return text;
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
javax.swing.JFrame frame = new javax.swing.JFrame("Test");
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
javax.swing.JComponent newContentPane = new SectionEditorPane();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
/**
* Main method for running the SectionEditorPane class.
*
* @param args a String array of command line arguments.
*/
public static void main(final String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
/**
* I needed to show the color chooser as a dialog but Java doesn't
* allow to customize the color chooser in a dialog, as I needed
* to. So, I had to copy over the Java built-in showDialog method and
* add my own modifications to it. Now, that method requires the
* following class to operate, so I had to copy it over as well.
*
* @author <a href="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</a>
* @version 1.0
*/
class ColorTracker implements ActionListener {
/**
* The color chooser associated with this object.
*/
private JColorChooser chooser;
/**
* The color currently selected in the chooser.
*/
private Color color;
/**
* Creates a new <code>ColorTracker</code> instance.
*
* @param c a <code>JColorChooser</code> value
*/
public ColorTracker(final JColorChooser c) {
chooser = c;
}
/**
* Listens to actions performed in the color chooser.
*
* @param e an <code>ActionEvent</code> value
*/
public final void actionPerformed(final ActionEvent e) {
color = chooser.getColor();
}
/**
* Returns the color selected by the chooser.
*
* @return a <code>Color</code> value
*/
public final Color getColor() {
return color;
}
}
}

View File

@@ -0,0 +1,248 @@
package nettext.client.gui;
import java.util.Vector;
import java.util.List;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
/*
* Removed for pmd
* import javax.swing.JButton;
*/
import javax.swing.BoxLayout;
import javax.swing.JToggleButton;
import javax.swing.JInternalFrame;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameAdapter;
import nettext.client.Client;
import nettext.document.DocumentSection;
import nettext.util.UIUtilities;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
/**
* Class SectionFrame: Will be shown any time the user wants to edit a
* section. Through here, the user can choose to lock the section,
* unlock the section, or send an update to the server.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 26, 2004) - Created the SectionFrame class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 26, 2004
*/
public final class SectionFrame extends JInternalFrame {
/**
* This is the section associated with this document.
*/
private DocumentSection section;
/**
* This is where the section will be edited.
*/
private SectionEditorPane editor;
/**
* The toggle button to lock and unlock the message.
*/
private JToggleButton lockToggle;
/**
* Creates a new <code>SectionFrame</code> instance.
*@param sec section
*/
public SectionFrame(final DocumentSection sec) {
super(ClientUISettings.TITLE_SECTION + sec.getSectionName(), //Title
true, //Resizable
true, //Closable
true, //Maximizable
true); //Iconifiable
this.setContentPane(createContentPane(sec));
this.setSize(ClientUISettings.SIZE_SECTION);
this.setLocation(ClientUISettings.LOCATION_SECTION);
//Define custom behaviour for closing:
this.setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
this.addInternalFrameListener(new InternalFrameAdapter() {
public void internalFrameClosing(InternalFrameEvent e) {
int docId = section.getDocumentId();
DocumentFrame parent = ClientUI.getInstance()
.getDocumentFrame(docId);
if (parent == null) {
System.out.println("SectionFrame: Could not find parent...");
return;
}
parent.hideSectionFrame(section.getSectionId());
}
});
setDocumentSection(sec);
}
/**
* Creates the content pane.
*
* @param sec a <code>Document</code> value
* @return a <code>JPanel</code> value
*/
private JPanel createContentPane(final DocumentSection sec) {
JPanel result = new JPanel(new BorderLayout());
editor = new SectionEditorPane();
editor.setSection(sec);
result.add(createControlPane(sec), BorderLayout.WEST);
result.add(editor, BorderLayout.CENTER);
return result;
}
/**
* Creates the panel with buttons to do stuff.
*
* @param sec a <code>Document</code> value
* @return a <code>JPanel</code> value
*/
private JPanel createControlPane(final DocumentSection sec) {
JPanel result = new JPanel();
/*
* Removed for pmd
* jButton currentButton = null;
*/
result.setLayout(new BoxLayout(result, BoxLayout.Y_AXIS));
// //Update:
// currentButton = UIUtilities.getInstance()
// .makeIconButton(ClientUISettings.SECTION_NAME_UPDATE,
// ClientUISettings.SECTION_TOOLTIP_UPDATE,
// ClientUISettings.SECTION_ICON_UPDATE,
// new ActionListener() {
// public void actionPerformed(ActionEvent ae) {
// }
// });
// result.add(currentButton);
// //Save:
// currentButton = UIUtilities.getInstance()
// .makeIconButton(ClientUISettings.SECTION_NAME_SAVE,
// ClientUISettings.SECTION_TOOLTIP_SAVE,
// ClientUISettings.SECTION_ICON_SAVE,
// new ActionListener() {
// public void actionPerformed(ActionEvent ae) {
// //Implement save request
// DocumentSection sec = getDocumentSection();
// sec.setSectionContents(getSectionEditorPane()
// .getHTML());
// section = sec;
// List data = new Vector();
// data.add(Client.getInstance().getUsername());
// data.add(getDocumentSection());
// Client.getInstance()
// .sendMessage(MessageFactory.getInstance()
// .makeMessage(MessageSettings
// .SECT_TRANSFER_TYPE,
// data));
// }
// });
// result.add(currentButton);
//Lock/Unlock:
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
//Implement lock request
String type = null;
if (((JToggleButton.ToggleButtonModel) lockToggle.getModel())
.isSelected()) {
type = MessageSettings.LOCK_SECT_TYPE;
getSectionEditorPane().setEnabled(true);
} else {
type = MessageSettings.UNLOCK_SECT_TYPE;
getSectionEditorPane().setEnabled(false);
}
List data = new Vector();
data.add(Client.getInstance().getUsername());
data.add(new Integer(section.getDocumentId()));
data.add(new Integer(section.getSectionId()));
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(type, data));
}
};
lockToggle = UIUtilities.getInstance()
.makeIconToggleButton(ClientUISettings.SECTION_NAME_UNLOCK,
ClientUISettings.SECTION_TOOLTIP_UNLOCK,
ClientUISettings.SECTION_ICON_UNLOCK,
al);
if (sec.isSectionLocked()) {
if (sec.getUserName().equals(Client.getInstance().getUsername())) {
getSectionEditorPane().setEnabled(true);
((JToggleButton.ToggleButtonModel) lockToggle.getModel())
.setSelected(true);
} else {
getSectionEditorPane().setEnabled(false);
((JToggleButton.ToggleButtonModel) lockToggle.getModel())
.setSelected(false);
lockToggle.setEnabled(false);
}
} else {
getSectionEditorPane().setEnabled(false);
((JToggleButton.ToggleButtonModel) lockToggle.getModel())
.setSelected(false);
}
result.add(lockToggle);
return result;
}
/**
* Get the value of section.
* @return value of section.
*/
public DocumentSection getDocumentSection() {
return section;
}
/**
* Set the value of section.
* @param v Value to assign to section.
*/
public void setDocumentSection(DocumentSection v) {
//FIXME: Update stuff.
this.section = v;
}
/**
* Get the value of editor.
* @return value of editor.
*/
public SectionEditorPane getSectionEditorPane() {
return editor;
}
/**
* Clears out the contents and hides the frame.
*/
public void clearAndHide() {
this.setVisible(false);
this.dispose();
}
}

View File

@@ -0,0 +1,265 @@
package nettext.client.gui;
import java.util.List;
import java.util.Vector;
import java.awt.Component;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import nettext.document.Document;
import nettext.document.DocumentSection;
import nettext.messaging.MessageFactory;
import nettext.messaging.MessageSettings;
import nettext.client.Client;
/**
* Class SectionListPane: will contain the list of sections together
* with their specifications, like the name of the user that last
* edited the section and the time stamp. As well, there will be a
* button to create new sections.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 26, 2004) - Created the SectionListPane class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 26, 2004
*/
public final class SectionListPane extends JPanel
implements ListSelectionListener {
/**
* The list model associated with the section list.
*/
private DefaultListModel listModel;
/**
* The list box in which the list of sections will be displayed.
*/
private JList sectionList;
/**
* The document whose sections are to be displayed.
*/
private Document document;
/**
* Creates a new <code>SectionListPane</code> instance.
*@param doc document
*/
public SectionListPane(final Document doc) {
super(new BorderLayout());
//this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
if (ClientUISettings.VERBOSE) {
System.out.println("SectionListPane: Constructing...");
System.out.flush();
}
JScrollPane scroller = null;
scroller = new JScrollPane(createSectionList());
updateSectionList(doc);
this.add(scroller, BorderLayout.CENTER);
this.add(createButtonPanel(), BorderLayout.SOUTH);
}
/**
* Creates the section list.
*
* @return a <code>JList</code> value
*/
private JList createSectionList() {
listModel = new DefaultListModel();
sectionList = new JList(listModel);
sectionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
sectionList.addListSelectionListener(this);
sectionList.setVisibleRowCount(8);
sectionList.setCellRenderer(new SectionItemRenderer());
return sectionList;
}
/**
* Creates the panel with the create section button.
*
* @return a <code>JPanel</code> value
*/
private JPanel createButtonPanel() {
JPanel result = new JPanel(new BorderLayout());
JButton newSection = new JButton("Create Section");
newSection.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (ClientUISettings.VERBOSE) {
System.out.println("SectionListPane: New section requested.");
System.out.flush();
}
String sectionName = ClientUI.getInstance()
.showInputDialog("Choose Section Name",
"Please input the name you would like the "
+ "section to have.",
"");
if (sectionName == null) { return; }
DocumentSection s = new DocumentSection(getDocument()
.getDocumentId());
s.setSectionName(sectionName);
s.setSectionOrder(getDocument().getSections().size());
s.setUserName(Client.getInstance().getUsername());
s.setSectionContents("Blank Section");
s.updateTimeStamp();
s.lockSection();
if (ClientUISettings.VERBOSE) {
System.out.println("SectionListPanel: Created new section - " + s);
System.out.flush();
}
List data = new Vector();
data.add(Client.getInstance().getUsername());
data.add(s);
Client.getInstance()
.sendMessage(MessageFactory.getInstance()
.makeMessage(MessageSettings.SECT_TRANSFER_TYPE,
data));
}
});
result.add(newSection, BorderLayout.CENTER);
return result;
}
/**
* Returns the document.
*
* @return a <code>Document</code> value
*/
public Document getDocument() {
return document;
}
/**
* Sets the new document to render.
*@param d document
*/
public void setDocument(final Document d) {
updateSectionList(d);
}
/**
* Rerenders the section list.
*
* @param newDoc a <code>Document</code> value
*/
public void updateSectionList(final Document newDoc) {
int numSections;
document = newDoc;
listModel.clear();
numSections = document.getSections().size();
for (int i = 0; i < numSections; i++) {
listModel.addElement(document.getSections().getSectionAt(i));
}
}
/**
* Invoked when an action occurs.
*
* @param e the event associated with the action.
*/
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
if (sectionList.getSelectedIndex() == -1) {
//No selection
return;
} else {
//Selection
DocumentSection selection
= (DocumentSection) sectionList.getSelectedValue();
DocumentFrame df = ClientUI.getInstance()
.getDocumentFrame(selection.getDocumentId());
if (df == null) {
System.out.println("SectionListPane: tried to view section"
+ " for nonexistent document.");
System.out.flush();
return;
}
df.addSectionFrame(selection);
}
}
}
/**
* This class will be used to render items in the list of sections.
*/
private final class SectionItemRenderer implements ListCellRenderer {
/**
* Creates a new <code>SectionItemRenderer</code> instance.
*/
public SectionItemRenderer() { }
/**
* Return a component that has been configured to display the
* specified value. That component's paint method is then called
* to "render" the cell. If it is necessary to compute the
* dimensions of a list because the list cells do not have a fixed
* size, this method is called to generate a component on which
* getPreferredSize can be invoked.
*
* @param list The JList we're painting.
* @param value The value returned by list.getModel().getElementAt(index).
* @param index The cell's index.
* @param isSelected True if the specified cell was selected.
* @param cellHasFocus True if the specified cell has the focus.
* @return A component whose paint() method will render the
* specified value.
*/
public Component getListCellRendererComponent(final JList list,
final Object value,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
String color = "";
if (isSelected) {
color = "#9400D3";
} else {
color = "blue";
}
return new JLabel("<html><font color=\"" + color + "\"><b><u>"
+ value.toString()
+ "</u></b></font>");
}
}
}

View File

@@ -0,0 +1,67 @@
package nettext.client.gui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import nettext.client.Client;
import nettext.util.UIUtilities;
/**
* Class ServerMenu: Will allow the user to create or import new documents.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 26, 2004) - Created the ServerMenu class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 26, 2004
*/
public class ServerMenu extends JMenuBar {
/**
* Creates a new <code>ServerMenu</code> instance.
*/
public ServerMenu() {
this.add(makeDocumentMenu());
}
/**
* Makes the file menu.
*
* @return a <code>JMenu</code> value
*/
private JMenu makeDocumentMenu() {
JMenu result = new JMenu("Document");
JMenuItem tempItem = null;
ActionListener l = null;
//New Document
l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Client.getInstance().createDocument();
}
};
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_NEW_NAME, KeyEvent.VK_N, l);
result.add(tempItem);
//Import Document
l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Client.getInstance().importDocument();
}
};
tempItem = UIUtilities.getInstance().
makeMenuItem(ClientUISettings.MENU_IMPORT_NAME, KeyEvent.VK_I, l);
result.add(tempItem);
return result;
}
}

View File

@@ -0,0 +1,3 @@
<body>
Package description goes here.
</body>

View File

@@ -0,0 +1,29 @@
package nettext.client.networking;
/**
* Class ClientNetworkSettings: Contains some settings for the client
* networking.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 01, 2004) - Created the ClientNetworkSettings class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 01, 2004
*/
public final class ClientNetworkSettings {
/**
* Display verbose output?
*/
public static final boolean VERBOSE = false;
/**
* Creates a new <code>ClientNetworkSettings</code> instance.
*/
private ClientNetworkSettings() {
}
}

View File

@@ -0,0 +1,156 @@
package nettext.client.networking;
import java.net.Socket;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import nettext.messaging.AbstractMessage;
/**
* Class ClientNetworking: This class performs all of the necessary
* communications with the server. It will send and receive messages,
* as well as notify the server when we want to quit, etc.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 31, 2004) - Created the ClientNetworking class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Jan. 31, 2004
*/
public class ClientNetworking {
/**
* The socket on which we want to connect to the server.
*/
private Socket socket;
/**
* Keeps track of whether the client is connected to a server or not.
*/
private boolean connected;
/**
* Contains the stream through which we can write to the socket.
*/
private PrintWriter socketWriter;
/**
* Creates a new <code>ClientNetworking</code> instance.
*/
public ClientNetworking() {
socket = null;
socketWriter = null;
connected = false;
}
/**
* Connects to the server at the specified location with the
* specified username. Returns true upon success, or false upon
* failure.
*
* @param host a <code>String</code> value
* @param port an <code>int</code> value
* @return a <code>boolean</code> value
*/
public final boolean connect(final String host,
final int port) {
socket = null;
connected = false;
//Try to open a connection:
try {
socket = new Socket(host, port);
} catch (IOException ioe) {
System.err.println("ClientNetworking: Could not connect to the server:");
System.err.println(ioe.getMessage());
socket = null;
connected = false;
return false;
}
//If we are still here, the connection was successfully opened.
//Get output stream:
try {
socketWriter =
new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (IOException ioe) {
System.err.println("ClientNetworking: Could not get output stream to "
+ "the server:\n" + ioe.getMessage());
try { socket.close(); } catch (IOException e) { socket = null; }
socket = null;
connected = false;
return false;
}
//Start the listener thread:
new Thread(new ServerListener(socket)).start();
if (ClientNetworkSettings.VERBOSE) {
System.out.println("ClientNetworking: Connected to server");
System.out.println("\t" + socket.getInetAddress().toString());
}
connected = true;
return true;
}
/**
* Returns true if the client is connected to a server, and false if
* it is not.
*
* @return a <code>boolean</code> value
*/
public final boolean isConnected() {
return connected;
}
/**
* Sends the abstract message over to the server.
*
* @param message an <code>AbstractMessage</code> value
*/
public final void sendMessage(final AbstractMessage message) {
if (ClientNetworkSettings.VERBOSE) {
System.out.println("ClientNetworking: Trying to send message");
System.out.println("\t" + message.tokenize());
System.out.println("Target: " + socket.getInetAddress().toString());
}
socketWriter.println(message.tokenize());
socketWriter.flush();
}
/**
* This function will shut down the connection to the server. It
* assumes that the QUIT message has already been issued, so it
* simply tells the server listener to stop listening, and closes
* the connection.
*/
public final void shutDown() {
if (ClientNetworkSettings.VERBOSE) {
System.out.println("ClientNetworking: Shutting down connection...");
}
try {
if (socketWriter != null) {
socketWriter.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException ioe) {
System.err.println("ClientNetworking: Couldn't even close the "
+ "connection cleanly...");
} finally {
socketWriter = null;
socket = null;
connected = false;
}
}
}

View File

@@ -0,0 +1,139 @@
package nettext.client.networking;
import java.net.Socket;
import java.security.InvalidParameterException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import nettext.messaging.AbstractMessage;
import nettext.messaging.MessageFactory;
import nettext.client.Client;
/*
* Removed for pmd
*import nettext.messaging.MessageSettings;
*import nettext.messaging.ServerErrorMessage;
*/
/**
* Class ServerListener: The server listener class will run in its own
* thread and listen to the messages sent by the server. If a message
* is received, it will create something meaningful out of it using
* the message factory, and then pass the message on to the main
* client class.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 31, 2004) - Created the ServerListener class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Jan. 31, 2004
*/
public class ServerListener implements Runnable {
/**
* Contains the socket on which we want to listen to the server.
*/
private Socket serverSocket;
/**
* A variable to keep track of when we should stop listening to the
* server.
*/
private boolean clientQuit;
/**
* Creates a new <code>ServerListener</code> instance.
* @param socket a <code>Socket</code> value
*/
public ServerListener(final Socket socket) {
this.serverSocket = socket;
if (!serverSocket.isBound()) {
throw new InvalidParameterException("ServerListener: "
+ "socket is not bound!");
}
clientQuit = true;
}
/**
* Stops the listener.
*/
public final void stop() {
this.clientQuit = true;
}
/**
* Listens to the messages from the server untill the clients says
* it's time to quit. Notifies the Client class when a message is
* received.
*/
public final void run() {
String message = null;
BufferedReader br = null;
AbstractMessage msg = null;
clientQuit = false;
//Open reader:
try {
br = new BufferedReader(new InputStreamReader(
serverSocket.getInputStream()));
} catch (IOException ioe) {
System.err.println("ServerListener: Could not open input "
+ "stream from the server.\n" + ioe.getMessage());
return;
}
while (!clientQuit) {
//Get next message:
try {
message = br.readLine();
if (ClientNetworkSettings.VERBOSE) {
System.out.println("ServerListerner: Got message from server");
System.out.println("\t" + message);
}
if (message == null) {
throw new IOException("Server has dropped the connection.");
}
} catch (IOException ioe) {
System.err.println("ServerListener: Could not read from server.\n"
+ ioe.getMessage());
//Notify the client that the server has quit
Client.getInstance().serverQuit();
return;
}
msg = MessageFactory.getInstance().makeMessage(message);
if (msg == null) {
//Got bad message format
//Client.getInstance().processBadMessage(message);
continue;
}
// if (msg.getMessageType().equals(MessageSettings.SERVER_ERROR_TYPE)) {
// //There's been an error on the server. Tell the client about it.
// Client.getInstance().processMessage(msg);
// }
//Break connection if the client couldn't recover after the error.
if (clientQuit) {
break;
}
//Send the message on to the client.
Client.getInstance().processMessage(msg);
}
}
}

View File

@@ -0,0 +1,6 @@
<body>
Package <code>nettext.client.networking</code> contains classes
pertinent to the networking components of the client side of the
NetText application. Here is contained everything the client needs to
be able to connect to the server and exchange messages with it.
</body>

View File

@@ -0,0 +1,3 @@
<body>
Package description goes here.
</body>

View File

@@ -0,0 +1,191 @@
package nettext.document;
/**
* This is the Main Document Class
* It is used to store Documents on the server for NetTeXt Editing
*
* @author <a href="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</a>
* @version 1.0
*/
public final class Document {
/**
* Store the Document Id Number.
*/
private int documentId;
/**
* Store the Document Name.
*/
private String documentName;
/**
* Store the sections of this Document.
*/
private SectionList sections;
/**
* Flag for storing Document update status.
*/
private boolean updated;
/**
* Flag for storing Document load status.
*/
private boolean loaded;
/**
* Creates a new <code>Document</code> instance.
*
*/
public Document() {
documentId = 0;
documentName = "";
sections = new SectionList();
setDocumentName("Default Empty Document");
updated = false;
loaded = false;
}
/**
* Returns the ID of this document.
*
* @return an <code>int</code> value
*/
public int getDocumentId() {
return this.documentId;
}
/**
* Returns the name of the document.
*
* @return a <code>String</code> value
*/
public String getDocumentName() {
return this.documentName;
}
/**
* Gives the document a new name.
*
* @param documentName a <code>String</code> value
*/
public void setDocumentName(final String documentName) {
this.documentName = documentName;
this.documentId = documentName.hashCode();
}
/**
* Returns true if the document has been updated lately and false if
* it has not been.
*
* @return a <code>boolean</code> value
*/
public boolean isDocumentUpdated() {
return updated;
}
/**
* Returns true if the document is loaded and false if it is not.
*
* @return a <code>boolean</code> value
*/
public boolean isDocumentLoaded() {
return loaded;
}
/**
* Describe <code>setDocumentLoaded</code> method here.
*
* @param v a <code>boolean</code> value
*/
public void setDocumentLoaded(final boolean v) {
loaded = v;
}
/**
* Registers the fact that the document has been updated.
*/
public void updateDocument() {
updated = true;
}
/**
* Registers the fact that the document has been saved.
*/
public void saveDocument() {
updated = false;
}
/**
* Inserts the new section at the position specified pass -1 into
* the position field to add the section to the end of the
* list. Returns true upon successful addition and false upon
* failure.
*
* @param s a <code>DocumentSection</code> value
* @param position an <code>int</code> value
* @return a <code>boolean</code> value
*/
public boolean addSection(final DocumentSection s, final int position) {
boolean result = false;
if (position == -1) {
result = sections.add(s);
} else {
result = sections.insert(s, position);
}
if (result) {
updateDocument();
}
return result;
}
/**
* Updates the text of the section.
*
* @param sectionId an <code>int</code> value
* @param newText a <code>String</code> value
* @return a <code>boolean</code> value
*/
public boolean updateSection(final int sectionId, final String newText) {
DocumentSection s = sections.getSection(sectionId);
if (s == null) {
return false;
}
s.setSectionContents(newText);
updateDocument();
return true;
}
/**
* Returns the list of sections. Note that if something is changed
* in this list, the updateDocument() function of this class
* ***MUST*** !!! be called. Otherwise everything will break.
*
* @return a <code>SectionList</code> value
*/
public SectionList getSections() {
return sections;
}
/**
* Returns a short string representation of the document.
*
* @return a <code>String</code> value
*/
public String toString() {
return this.getDocumentName();
}
}

View File

@@ -0,0 +1,159 @@
package nettext.document;
import java.util.List;
import java.util.Vector;
/**
* Class DocumentList will contain a list of all documents on the server.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 15, 2004) - Created the DocumentList class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@mail.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Feb. 15, 2004
*/
public class DocumentList {
/**
* This is the list of all documents.
*/
private List documents;
/**
* Creates a new <code>DocumentList</code> instance.
*/
public DocumentList() {
documents = new Vector();
}
/**
* Goes through the list of already existing docs and if the
* doc with the same docId already exists, does not add this
* new doc to the list, and returns false. If no doc with the
* same docId already exists, then adds this new doc to the
* list and returns true.
*
* @param doc a <code>Document</code> value
* @return a <code>boolean</code> value
*/
public final boolean addDocument(final Document doc) {
if (size() == 0) {
documents.add(doc);
return true;
}
for (int i = 0; i < size(); i++) {
if (((Document) documents.get(i)).getDocumentId()
== doc.getDocumentId()) {
return false;
}
}
documents.add(doc);
return true;
}
/**
* Returns the object corresponding to the document, whose name is
* passed in.
*
* @param name of a doca <code>String</code> value
* @return a <code>Document</code> value
*/
public final Document getDocument(final String name) {
DocumentListIterator listIter = new DocumentListIterator(this);
while (listIter.hasNext()) {
Document current = listIter.next();
if (current.getDocumentName().equals(name)) {
return current;
}
}
return null;
}
/**
* Returns the object corresponding to the doc, whose docId is
* passed in.
*
* @param id a <code>int</code> value
* @return a <code>Document</code> value
*/
public final Document getDocument(final int id) {
DocumentListIterator listIter = new DocumentListIterator(this);
while (listIter.hasNext()) {
Document current = listIter.next();
if (current.getDocumentId() == id) {
return current;
}
}
return null;
}
/**
* Simply removes all the docs from the list. Doesn't notify
* anybody or anything, just calls clear on the doc vector.
*/
public final void clear() {
documents.clear();
}
/**
* Returns a Document list iterator that points to the first element
* of the vector.
*
* @return a <code>DocumentListIterator</code> value
*/
public final DocumentListIterator getIterator() {
return new DocumentListIterator(this);
}
/**
* Tests if there are no docs.
*
* @return a <code>boolean</code> value
*/
public final boolean isEmpty() {
return documents.isEmpty();
}
/**
* Removes the doc passed in from the list if it is present
* there.
*
* @param doc a <code>Document</code> value
*/
public final void removeDocument(final Document doc) {
int index = documents.indexOf(doc);
if (index >= 0) {
documents.remove(index);
}
}
/**
* Returns the number of docs currently available.
*
* @return an <code>int</code> value
*/
public final int size() {
return documents.size();
}
/**
* Returns the doc at the specified index in the vector.
*
* @param index an <code>int</code> value
* @return a <code>Document</code> value
*/
protected final Document elementAt(final int index) {
return (Document) documents.get(index);
}
}

View File

@@ -0,0 +1,60 @@
package nettext.document;
/**
* Class DocumentListIterator: This allows the server to iterate through
* the list of docs.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 25, 2004) - Created the DocumentListIterator class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 25, 2004
*/
public class DocumentListIterator {
/**
* The list we are iterating through.
*/
private DocumentList list;
/**
* The index at which we are currently pointing.
*/
private int currentIndex;
/**
* Creates a new <code>DocumentListIterator</code> instance.
*

View File

@@ -0,0 +1,238 @@
package nettext.document;
import java.util.Date;
import java.text.DateFormat;
/**
* This class holds data necessary for a given Document Section
*
* @author <a href="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</a>
* @version 1.0
*/
public class DocumentSection {
/**
* The id of the document that the section belongs to.
*/
private int documentId;
/**
* The Id number associated with this section.
*/
private int sectionId;
/**
* The order in which the section appears in the document.
*/
private int sectionOrder;
/**
* The date of the last edit, or when the section was locked.
*/
private Date timeStamp;
/**
* Contains true if the section is locked and should not be edited.
*/
private boolean sectionLocked;
/**
* Store the sectionName of this Section
*/
private String sectionName;
/**
* The string with the contents of the section.
*/
private String sectionContents;
/**
* The name of the author of the latest update.
*/
private String userName;
/**
* Creates a new <code>DocumentSection</code> instance.
*
* @param docId The id of the document that the section belongs to.
*/
public DocumentSection(final int docId) {
documentId = docId;
sectionId = 0;
sectionOrder = -1;
timeStamp = null;
sectionLocked = false;
sectionName = "";
sectionContents = "";
}
/**
* Get the value of documentId.
* @return value of documentId.
*/
public final int getDocumentId() {
return documentId;
}
/**
* Set the value of documentId.
* @param v Value to assign to documentId.
*/
public final void setDocumentId(final int v) {
this.documentId = v;
}
/**
* Get the value of sectionId.
* @return value of sectionId.
*/
public final int getSectionId() {
return sectionId;
}
/**
*set the section id.
*@param id section id.
*/
public final void setSectionId(int id) {
this.sectionId = id;
}
/**
* Get the value of sectionOrder.
* @return value of sectionOrder.
*/
public final int getSectionOrder() {
return sectionOrder;
}
/**
* Set the value of sectionOrder.
* @param v Value to assign to sectionOrder.
*/
public final void setSectionOrder(final int v) {
this.sectionOrder = v;
}
/**
* Get the value of sectionLocked.
* @return value of sectionLocked.
*/
public final boolean isSectionLocked() {
return sectionLocked;
}
/**
* Get the value of timeStamp.
* @return value of timeStamp.
*/
public final Date getTimeStamp() {
return timeStamp;
}
/**
* Set the value of timeStamp.
* @param timeS value of timeStamp.
*/
public final void setTimeStamp(Date timeS) {
this.timeStamp = timeS;
}
/**
* Sets the timestamp to the current time.
*/
public final void updateTimeStamp() {
timeStamp = new Date();
}
/**
* Locks the section.
*/
public final void lockSection() {
sectionLocked = true;
}
/**
* Unlocks the section.
*/
public final void unlockSection() {
sectionLocked = false;
}
/**
* Returns the name of the latest author.
*
* @return a <code>String</code> value
*/
public final String getUserName() {
return this.userName;
}
/**
* Gives the section a new name.
*
* @param name a <code>String</code> value
*/
public final void setUserName(final String name) {
this.userName = name;
}
/**
* Returns the name of the section.
*
* @return a <code>String</code> value
*/
public final String getSectionName() {
return this.sectionName;
}
/**
* Gives the section a new name.
*
* @param name a <code>String</code> value
*/
public final void setSectionName(final String name) {
this.sectionId = name.hashCode();
this.sectionName = name;
}
/**
* Get the value of sectionContents.
* @return value of sectionContents.
*/
public final String getSectionContents() {
return sectionContents;
}
/**
* Set the value of sectionContents.
* @param v Value to assign to sectionContents.
*/
public final void setSectionContents(final String v) {
this.sectionContents = v;
}
/**
* Returns a string representation of the section.
*
* @return a <code>String</code> value
*/
public final String toString() {
String text = "";
//String dateString = ""; // removed for pmd
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT);
text += getSectionName() + " ";
text += "<font size=\"1\">(";
text += (isSectionLocked() ? "Locked" : "Last Edited");
text += " by " + getUserName();
text += " on " + df.format(getTimeStamp());
text += ")</font>";
return text;
}
}

View File

@@ -0,0 +1,177 @@
package nettext.document;
import java.util.List;
import java.util.Vector;
/**
* Class SectionList: Contains the list of sections belonging to the
* document.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 18, 2004) - Created the SectionList class
* </PRE>
*
* @author <A HREF="mailto:gtg308i@mail.gatech.edu">Vladimir Urazov</A>
* @version Version 1.0, Feb. 18, 2004
*/
public final class SectionList {
/**
* Contains the list of sections in the document.
*/
private List sections;
/**
* Creates a new <code>SectionList</code> instance.
*/
public SectionList() {
sections = new Vector();
}
/**
* Attempts to add the new section to the end of the document. Will
* return true if the addition succeeds and false if it fails.
*
* @param section a <code>DocumentSection</code> value
* @return a <code>boolean</code> value
*/
public synchronized boolean add(final DocumentSection section) {
DocumentSection test = getSection(section.getSectionId());
if (test == null) {
sections.add(section);
section.setSectionOrder(size() - 1);
return true;
}
return false;
}
/**
* Attempts to insert the section at the sectionOrder specified. Returns
* true if the insertion succeeds and false if it fails.
*
* @param section a <code>DocumentSection</code> value
* @param sectionOrder an <code>int</code> value
* @return a <code>boolean</code> value
*/
public synchronized boolean insert(final DocumentSection section,
final int sectionOrder) {
DocumentSection test = getSection(section.getSectionId());
if (test == null) {
sections.add(sectionOrder, section);
updateSectionOrders(sectionOrder);
return true;
}
return false;
}
/**
* Returns the section at the specified sectionOrder.
*
* @param sectionOrder an <code>int</code> value
* @return a <code>DocumentSection</code> value
*/
public synchronized DocumentSection getSectionAt(final int sectionOrder) {
return (DocumentSection) sections.get(sectionOrder);
}
/**
* Returns the section at the specified index.
*@param index an <code>int </code> value
*@return a <code> DocumentSection </code>value
*/
public synchronized DocumentSection get(final int index) {
return (DocumentSection) sections.get(index);
}
/**
* Returns the section with the specified id if one exists, or null
* if there is no such section.
*
* @param sectionId an <code>int</code> value
* @return a <code>DocumentSection</code> value
*/
public synchronized DocumentSection getSection(final int sectionId) {
DocumentSection temp = null;
for (int i = 0; i < size(); i++) {
temp = (DocumentSection) sections.get(i);
if (temp.getSectionId() == sectionId) {
return temp;
}
}
return null;
}
/**
* Clears the list of sections.
*/
public synchronized void clear() {
sections.clear();
}
/**
* Returns the number of elements in the section list.
*
* @return an <code>int</code> value
*/
public int size() {
return sections.size();
}
/**
* Removes the section at the specified sectionOrder, and returns
* it. Returns null if no such section exists.
*
* @param sectionOrder an <code>int</code> value
* @return a <code>DocumentSection</code> value
*/
public synchronized DocumentSection removeSectionAt(final int sectionOrder) {
return (DocumentSection) sections.remove(sectionOrder);
}
/**
* Removes the section with the specified id, and returns
* it. Returns null if no such section exists.
*
* @param secId an <code>int</code> value
* @return a <code>DocumentSection</code> value
*/
public synchronized DocumentSection removeSection(final int secId) {
DocumentSection temp = null;
for (int i = 0; i < size(); i++) {
temp = (DocumentSection) sections.get(i);
if (temp.getSectionId() == secId) {
//Found the section to remove...
sections.remove(i);
updateSectionOrders(i);
return temp;
}
}
return null;
}
/**
* Updates the sectionOrders of the sections starting from the start
* index.
*
* @param start an <code>int</code> value
*/
protected synchronized void updateSectionOrders(final int start) {
for (int i = start; i < size(); i++) {
getSectionAt(i).setSectionOrder(i);
}
}
}

View File

@@ -0,0 +1,3 @@
<body>
Package description goes here.
</body>

View File

@@ -0,0 +1,103 @@
package nettext.file;
import nettext.document.Document;
import nettext.document.DocumentSection;
import java.io.BufferedReader;
/**
* This class is the ASCII-format Document Reader
* which is used by DocumentReader to read-in ASCII Documents
*
* Parsing Format:
* "\n\n" is a new section
*
*/
public class ASCIIDocumentReader extends DocumentReader {
/**
* This stores the Document to be read.
*/
private Document document;
/**
* Current Document Section being doing stuff to.
*/
private DocumentSection docSection;
/**
* Read in a Document
* @return success in reading the Document
*/
public Document readDocument() {
document = new Document();
BufferedReader br;
docSection = null;
String sCurrSect = "";
String sCurrSectName = "";
String sCurrText;
int iSectionOrder = 0;
br = new BufferedReader(this.getInFileReader());
try {
sCurrText = br.readLine();
if (sCurrText == null) {
return null;
}
} catch (java.io.IOException ioe) {
//readLine failed, returning blank document
return null;
}
document.setDocumentName(sCurrText);
try {
while ((sCurrText = br.readLine()) != null) {
// Checking current line for "..."
if (sCurrText.startsWith("...")) {
//Creating a new section
if (docSection == null) {
docSection =
new DocumentSection(document.getDocumentId());
sCurrSectName = sCurrText.substring(3);
continue;
} else { //Adding section and resetting section info
docSection.setSectionOrder(iSectionOrder);
docSection.setSectionName(sCurrSectName);
docSection.setSectionContents(sCurrSect);
docSection.updateTimeStamp();
docSection.setUserName("Server");
document.addSection(docSection, iSectionOrder++);
//Done adding section, creating new docsec
docSection =
new DocumentSection(document.getDocumentId());
sCurrSectName = sCurrText.substring(3);
sCurrSect = "";
continue;
}
}
sCurrSect += sCurrText;
}
// No more lines but we need to add current section
if (docSection != null) {
docSection.setSectionOrder(iSectionOrder);
docSection.setSectionName(sCurrSectName);
docSection.setSectionContents(sCurrSect);
docSection.updateTimeStamp();
docSection.setUserName("Server");
document.addSection(docSection, iSectionOrder++);
}
} catch (java.io.IOException ioe) {
//readLine failed, returning what we have of the document
document.setDocumentLoaded(true);
return document;
}
document.setDocumentLoaded(true);
return document;
}
}

View File

@@ -0,0 +1,152 @@
package nettext.file;
import nettext.document.Document;
import nettext.document.DocumentSection;
import java.io.IOException;
import java.io.PrintWriter;
/**
* This class defines the ASCIIOutputHandler operations required by
* DocumentOutputHandlers.
*/
public class ASCIIOutputHandler implements DocumentOutputHandler {
/**
* The Writer
*/
private java.io.PrintWriter oStream;
/**
* The Writee
*/
private String fileName;
/**
* Standard Initialization function that initializes all fields
* to default values
* @param filename , filename to try to write to
* @return boolean , whether or not initialization was successful
*/
public boolean initialize(String filename) {
if (filename == null) {
return false;
}
this.fileName = filename;
//initialize the PrintWriter
try {
oStream = new PrintWriter(new java.io.FileOutputStream(filename));
} catch (IOException ioe) {
System.err.println("Error initializing Output Handler");
return false;
}
return true;
}
/**
* Flush/Close Buffers/Streams
*/
public void cleanUp() {
oStream.flush();
oStream.close();
}
/**
* Write the things at the start of the File
*/
public void startFile() {
}
/**
* Write out the things related to ending the file
*/
public void endFile() {
}
/**
* Write out the things necessary to start the Document itself
* @param doc , the document to write the start of
*/
public void startDocument(Document doc) {
try {
//Print out the document name
this.writeOut(doc.getDocumentName());
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, startDocument()-ASCIIOH");
}
}
/**
* Write out the things necessary to close the Document
*/
public void endDocument() {
}
/**
* Write out a section of a given Document
* @param docSec , the section to write out
*/
public void writeSection(DocumentSection docSec) {
try {
//Print out a section of a document.
this.writeOut("..." + docSec.getSectionName());
this.nl();
this.writeOut(docSec.getSectionContents());
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, writeSection()-ASCIIOH");
}
}
/**
* Write out entire file
* @param doc , document to write out
* @return boolean , whether or not operation was successful
*/
public boolean writeToDisk(Document doc) {
this.startDocument(doc);
nettext.document.SectionList secList = doc.getSections();
for (int i = 0; i < secList.size(); i++) {
this.writeSection(secList.getSectionAt(i));
}
this.cleanUp();
return true;
}
/*
* Helper Hunctions
*/
/**
* Helper function
* Writes the String toWrite to the stdOut
* @param toWrite , string to write out
* @throws IOException , thrown if error in writing
*/
private void writeOut(String toWrite) throws IOException {
oStream.print(toWrite);
oStream.flush();
}
/**
* Helper function
* Writes a newline to the file
* @throws IOException , throws if error in writing
*/
private void nl() throws IOException {
//flush once for the bulk, twice for the left-overs
oStream.print("\n");
oStream.flush();
}
}

View File

@@ -0,0 +1,200 @@
package nettext.file;
import nettext.document.Document;
import nettext.document.DocumentList;
import java.io.File;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
/**
* Reader for the available list of Documents
*/
public class DocumentListReader extends DefaultHandler {
/**
* This stores the Document to be read
*/
private DocumentList documentList;
/**
* The fileName of the File read in
*/
private String fileName;
/**
* Creates a new <code>DocumentListReader</code> instance.
*/
public DocumentListReader() {
documentList = new DocumentList();
fileName = null;
}
/**
* Initialize the Document Reader.
* Read through Repository and open streams for Documents
*@param fileN filename
* @return successful if true
*/
public boolean initialize(String fileN) {
this.fileName = fileN;
documentList.clear();
return true;
}
/**
* Close streams and stuff.
*/
public void cleanUp() {
fileName = null;
}
/**
* Read in document list.
* @return Document a new Document as read in
*/
public DocumentList readDocumentList() {
//Do the parsing
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Parse the input
SAXParser saxParser = factory.newSAXParser();
File f = new File(fileName);
if (XMLSettings.VERBOSE) {
System.out.println("DocumentListReader: Reading from file:");
System.out.println("\t" + f.getAbsolutePath());
System.out.flush();
}
saxParser.parse(f, this);
} catch (Exception exc) {
System.err.println("DocumentListReader: Got an error:");
System.err.println("\t" + exc.getClass().getName() + ": "
+ exc.getMessage());
return null;
}
return documentList;
}
/**
* Processes the start of an XML element.
*
* @param uri a <code>String</code> value
* @param localName a <code>String</code> value
* @param qName a <code>String</code> value
* @param att an <code>Attributes</code> value
* @exception SAXException if an error occurs
*/
public void startElement(final String uri,
final String localName,
final String qName,
final Attributes att) throws SAXException {
String name = localName;
if (name == null || name.equals("")) {
name = qName;
}
//Grab in the case of a new Document
if (name.equals(XMLSettings.DOCUMENT_LIST)) {
if (documentList != null) {
this.documentList.clear();
} else {
System.err.println("DocListReader: Could not read"
+ " Document List. Syntax Error");
documentList = null;
return;
}
} else if (name.equals(XMLSettings.DOCUMENT_KEY)) {
/* - Variables - */
String docName = null; //hash the name to get the ID
String docID = null; //useless fellow, ID is just hash
String attributeName = null; //store the currently read attribute
//Loop through the variables
for (int i = 0; i < att.getLength(); i++) {
//get Current attribute
attributeName = att.getLocalName(i);
if (attributeName == null || attributeName.equals("")) {
attributeName = att.getQName(i);
}
//Check the current Attribute
if (attributeName.equals("name")) {
docName = att.getValue(i);
} else if (attributeName.equals("id")) {
docID = att.getValue(i);
} else {
System.err.println("DocListReader: Unknown attribute: "
+ attributeName + "="
+ att.getValue(i));
}
}
//Ensure all (Required) Fields met
if (docName == null) {
System.err.println("DocListReader: Could not read"
+ " Document. Syntax Error");
this.documentList = null;
return;
}
Document tempDoc = new Document();
tempDoc.setDocumentName(docName);
//Perform necessary actions with fields
this.documentList.addDocument(tempDoc);
} else {
//Output the bad tag
System.err.println("DocListReader: Unknown tag: <" + name + ">");
return;
}
}
/**
* Processes string data within an XML element.
*
* @param ch a <code>char[]</code> value
* @param start an <code>int</code> value
* @param length an <code>int</code> value
*
*/
public void characters(char[] ch, int start, int length) {
if (false) {
System.err.println("DocListReader: Unexpected characters: \""
+ ch + "\"");
}
}
/**
* Processes the end of an XML element.
*
* @param namespaceURI a <code>String</code> value
* @param localName a <code>String</code> value
* @param qName a <code>String</code> value
*
*/
public void endElement(String namespaceURI,
String localName, String qName) {
String name = localName;
if (name == null || name.equals("")) {
name = qName;
}
if (false) {
System.out.println("DocumentListReader: Got closing tag: </"
+ name + ">");
}
}
}

View File

@@ -0,0 +1,203 @@
package nettext.file;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.FileOutputStream;
import nettext.document.Document;
import nettext.document.DocumentList;
import nettext.document.DocumentListIterator;
/**
* Writer for the available list of Documents
*/
public class DocumentListWriter {
/**
* The Writer.
*/
private PrintWriter oStream;
/**
* The Writee.
*/
private String fileName;
/**
* Standard Initialization function that initializes all fields
* to default values
*@param fileN afilename
*@return boolean
*/
public boolean initialize(String fileN) {
if (fileN == null) {
return false;
}
this.fileName = fileN;
//initialize the PrintWriter
try {
oStream = new PrintWriter(new FileOutputStream(fileName));
} catch (IOException ioe) {
System.err.println("Error initializing list writer:");
System.err.println("\t" + ioe.getMessage());
System.err.flush();
return false;
}
return true;
}
/**
* Flush/Close Buffers/Streams
*/
public void cleanUp() {
oStream.flush();
oStream.close();
oStream = null;
}
/**
* Writes the document list if possible.
*
* @param list a <code>DocumentList</code> value
* @return a <code>boolean</code> value
*/
public boolean writeDocumentList(final DocumentList list) {
DocumentListIterator dli = list.getIterator();
if (oStream == null) {
return false;
}
//Start file
if (!startFile()) { return false; }
//Start list
if (!startList(list)) { return false; }
//Write documents
while (dli.hasNext()) {
if (!writeDocument(dli.next())) { return false; }
}
//End list
if (!endList()) { return false; }
//End file
if (!endFile()) { return false; }
return true;
}
/**
* Write the things at the start of the File
*@return boolean
*/
public boolean startFile() {
try {
//Print out the start of the document.
this.writeOut("<?xml version='1.0'?>");
this.nl();
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, startFile()-NTOH");
return false;
}
return true;
}
/**
* Write out the things related to ending the file
* @return a <code>boolean</code> value
*/
public boolean endFile() {
return true;
}
/**
* Writes the start of the document list into the file.
*
* @param list a <code>DocumentList</code> value
* @return a <code>boolean</code> value
*/
public boolean startList(final DocumentList list) {
try {
this.writeOut("<" + XMLSettings.DOCUMENT_LIST);
this.writeOut(" numDocuments=\"" + list.size() + "\"");
this.writeOut(">");
this.nl();
} catch (IOException ioe) {
System.err.println("IO Exception!! startList() - NTOH");
return false;
}
return true;
}
/**
* Writes out the end of the document list into the file.
*
* @return a <code>boolean</code> value
*/
public boolean endList() {
try {
this.writeOut("</" + XMLSettings.DOCUMENT_LIST + ">");
this.nl();
} catch (IOException ioe) {
System.err.println("IO Exception!! endList() - NTOH");
return false;
}
return true;
}
/**
* Write out the document.
* @param toWrite a <code>Document</code> value
* @return a <code>boolean</code> value
*/
public boolean writeDocument(Document toWrite) {
try {
// Figure out the writeOut (the docName shouldn't be fileName!)
this.writeOut("\t<"
+ XMLSettings.DOCUMENT_KEY
+ " name=\""
+ toWrite.getDocumentName()
+ "\" id=\""
+ toWrite.getDocumentId()
+ "\" />");
this.nl();
} catch (IOException ioe) {
System.err.println("IO Exception!! startDocument() - NTOH");
return false;
}
return true;
}
/**
* Helper function
* Writes the String toWrite to the stdOut
*@param toWrite toWrite
*@throws IOException exception
*/
private void writeOut(String toWrite) throws IOException {
oStream.print(toWrite);
oStream.flush();
}
/**
* Helper function
* Writes a newline to the file
*@throws IOException exception
*/
private void nl() throws IOException {
//flush once for the bulk, twice for the left-overs
oStream.print("\n");
oStream.flush();
}
}

View File

@@ -0,0 +1,52 @@
package nettext.file;
/**
* This interface defines the standard functions required by all
* DocumentOutputHandlers.
*/
public interface DocumentOutputHandler {
/**
* Standard Initialization function that initializes all fields
* to default values
*@param fileName fileName
*@return boolean
*/
public boolean initialize(String fileName);
/**
* Flush/Close Buffers/Streams
*/
public void cleanUp();
/**
* FIXME - javadoc
* Does something related to starting a File
*/
public void startFile();
/**
* FIXME - javadoc
* Does somthing related to ending a File
*/
public void endFile();
/**
* FIXME - javadoc
* Does something related to starting a Document
*@param doc document
*/
public void startDocument(nettext.document.Document doc);
/**
* FIXME - javadoc
* Does something related to ending a Document
*/
public void endDocument();
/**
* Write out a section of a given Document
*@param docSec documentSection
*/
public void writeSection(nettext.document.DocumentSection docSec);
}

View File

@@ -0,0 +1,145 @@
package nettext.file;
import java.io.FileReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import nettext.document.Document;
/**
* This class is the main Document Reader from which
* all document types can be read and referenced
*/
public abstract class DocumentReader {
/**
* The fileReader to read Files
*/
private FileReader inFileReader;
/**
* The File pointer
*/
private File inFile;
/**
* The fileName of the File read in
*/
private String fileName;
/**
* Initialize the Document Reader
* Read through Repository and open streams for Documents
* @param fileN file
* @return successful if true
*/
public boolean initialize(String fileN) {
try {
this.inFile = new File(fileN);
this.inFileReader = new FileReader(this.inFile);
} catch (FileNotFoundException fnfe) {
System.err.println("File Not Found, initialize(String)");
return false;
}
this.fileName = fileN;
return true;
}
/**
* Flush/Close Buffers/Streams
*@return boolean
*/
public boolean cleanUp() {
try {
inFileReader.close();
} catch (IOException ioe) {
System.err.println("Error Closing File, cleanUp(), DocReader\n");
return false;
}
return true;
}
/**
* Read in a Document
*
* @return success in reading the Document
*/
public abstract Document readDocument();
/**
* Method setInFileReader
*
*
* @param inFileReader in
*
*/
public void setInFileReader(FileReader inFileReader) {
this.inFileReader = inFileReader;
}
/**
* Method setInFile
*
*
* @param inFile file
*
*/
public void setInFile(File inFile) {
this.inFile = inFile;
}
/**
* Method setFileName
*
*
* @param fileName file
*
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* Method getInFileReader
*
*
* @return filereader
*
*/
public FileReader getInFileReader() {
return (this.inFileReader);
}
/**
* Method getInFile
*
*
* @return file
*
*/
public File getInFile() {
return (this.inFile);
}
/**
* Method getFileName
*
*
* @return fileName
*
*/
public String getFileName() {
return (this.fileName);
}
}

View File

@@ -0,0 +1,34 @@
package nettext.file;
import nettext.document.Document;
/**
* This class is the main Document Writer from which
* all document types can be written
*/
public class DocumentWriter {
/**
* The reference to a DocumentOutputHandler, which contains
* the methods necessary for writing out the files
*/
private DocumentOutputHandler outputHandler = null;
/**
* Set the OutputHandler
* @param outputHandler the new outputHandler to use
*/
public final void setOutputHandler(final DocumentOutputHandler
outputHandler) {
this.outputHandler = outputHandler;
}
/**
* Write the document using the current outputHandler
*@param document document
* @return success of write operation
*/
public final boolean writeDocument(final Document document) {
return false;
}
}

View File

@@ -0,0 +1,165 @@
package nettext.file;
import nettext.document.Document;
import nettext.document.DocumentSection;
import java.io.BufferedReader;
/**
* This class is the HTML-format Document Reader
* which is used by DocumentReader to read-in HTML Documents
*/
public class HTMLDocumentReader extends DocumentReader {
/**
* This stores the Document to be read.
*/
private Document document;
/**
* Current Document Section being doing stuff to.
*/
private DocumentSection docSection;
/**
* Read in a Document
* @return success in reading the Document
*/
public Document readDocument() {
document = new Document();
Document docError = new Document();
BufferedReader br;
docSection = null;
String sCurrSect = "";
String sCurrSectName = null;
String sCurrText;
int iSectionOrder = 0;
int iPos1 = -1;
int iPos2 = -1;
boolean bInSection = false;
br = new BufferedReader(this.getInFileReader());
try {
while ((sCurrText = br.readLine()) != null) {
//Reading Document name
if ((sCurrText.indexOf("<h2>") != -1)
|| (sCurrText.indexOf("<H2>") != -1)) {
iPos1 = sCurrText.lastIndexOf("<h2>");
if (iPos1 == -1) {
iPos1 = sCurrText.lastIndexOf("<H2>");
}
if ((sCurrText.indexOf("</h2>") != -1)
|| (sCurrText.indexOf("</H2>") != -1)) {
iPos2 = sCurrText.indexOf("</h2>");
}
if (iPos2 == -1) {
iPos2 = sCurrText.indexOf("</H2>");
}
if (iPos2 == -1) {
iPos2 = sCurrText.length();
}
//Setting the document name
document.setDocumentName(sCurrText.substring(iPos1, iPos2)
.replaceAll("<H2>", "").replaceAll("<h2>", ""));
break;
}
}
//This File does not have an H2 tag, so it doens't fit our format
if (sCurrText == null) {
DocumentSection secError =
new DocumentSection(docError.getDocumentId());
docError.setDocumentName("DocumentFormatError");
secError.setSectionName("HTML format error");
secError.setSectionContents(
"The HTML file that was requested has a format error.\n");
secError.updateTimeStamp();
secError.setUserName("Server");
docError.addSection(secError, 0);
docError.setDocumentLoaded(true);
return docError;
}
//Get section name and contents
while ((sCurrText = br.readLine()) != null) {
//Reading section name
if ((sCurrText.indexOf("<h3>") != -1)
|| (sCurrText.indexOf("<H3>") != -1)) {
iPos1 = sCurrText.lastIndexOf("<h3>");
if (iPos1 == -1) {
iPos1 = sCurrText.lastIndexOf("<H3>");
}
if ((sCurrText.indexOf("</h3>") != -1)
|| (sCurrText.indexOf("</H3>") != -1)) {
iPos2 = sCurrText.indexOf("</h3>");
}
if (iPos2 == -1) {
iPos2 = sCurrText.length();
}
if (docSection == null) {
docSection =
new DocumentSection(document.getDocumentId());
sCurrSectName = sCurrText.substring(iPos1, iPos2)
.replaceAll("<H3>", "").replaceAll("<h3>", "");
bInSection = true;
} else {
// adding section
docSection.setSectionOrder(iSectionOrder);
docSection.setSectionName(sCurrSectName);
docSection.setSectionContents(sCurrSect);
docSection.updateTimeStamp();
docSection.setUserName("Server");
document.addSection(docSection, iSectionOrder++);
//Done adding section, creating new docsec
docSection =
new DocumentSection(document.getDocumentId());
sCurrSectName = sCurrText.substring(iPos1, iPos2);
sCurrSect = "";
bInSection = true;
}
continue;
}
if (sCurrText.indexOf("</body>") != -1
|| sCurrText.indexOf("</BODY>") != -1) {
bInSection = false;
}
if (bInSection) {
sCurrSect += sCurrText;
}
}
// Adding last section if there is one
if (docSection != null) {
// adding section
docSection.setSectionOrder(iSectionOrder);
docSection.setSectionName(sCurrSectName);
docSection.setSectionContents(sCurrSect);
docSection.updateTimeStamp();
docSection.setUserName("Server");
document.addSection(docSection, iSectionOrder++);
}
} catch (java.io.IOException ioe) {
//readLine failed, returning what we have of the document
document.setDocumentLoaded(true);
return document;
}
document.setDocumentLoaded(true);
return document;
}
}

View File

@@ -0,0 +1,191 @@
package nettext.file;
import nettext.document.Document;
import nettext.document.DocumentSection;
import java.io.IOException;
import java.io.PrintWriter;
/**
* This class defines the HTMLOutputHandler operations required by
* DocumentOutputHandlers.
*/
public class HTMLOutputHandler implements DocumentOutputHandler {
/**
* The Writer
*/
private java.io.PrintWriter oStream;
/**
* The Writee
*/
private String fileName;
/**
* Standard Initialization function that initializes all fields
* to default values
* @param filename , name of file to try to write to
* @return boolean , whether or not the initialization was successfull
*/
public boolean initialize(String filename) {
if (filename == null) {
return false;
}
this.fileName = filename;
//initialize the PrintWriter
try {
oStream = new PrintWriter(new java.io.FileOutputStream(filename));
} catch (IOException ioe) {
System.err.println("Error initializing Output Handler");
return false;
}
return true;
}
/**
* Flush/Close Buffers/Streams
*/
public void cleanUp() {
oStream.flush();
oStream.close();
}
/**
* Write the things at the start of the File
*/
public void startFile() {
try {
this.writeOut("<html>");
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, startFile()-HTMLOH");
}
}
/**
* Write out the things related to ending the file
*/
public void endFile() {
try {
this.writeOut("</html>");
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, endFile()-HTMLOH");
}
}
/**
* Write out the things necessary to start the Document itself
* @param doc , document to start
*/
public void startDocument(Document doc) {
try {
this.writeOut("<head>");
this.nl();
this.writeOut("<title>" + doc.getDocumentName() + "</title>");
this.nl();
this.writeOut("</head>");
this.nl();
this.writeOut("<body>");
this.nl();
this.writeOut("<H2>");
this.writeOut(doc.getDocumentName());
this.writeOut("</H2>");
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, startDocument()-HTMLOH");
}
}
/**
* Write out the things necessary to close the Document
*/
public void endDocument() {
try {
this.writeOut("</body>");
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, endDocument()-HTMLOH");
}
}
/**
* Write out a section of a given Document
* @param docSec , DocumentSection to write out
*/
public void writeSection(DocumentSection docSec) {
try {
//Write an H3 tag of the section name
this.writeOut("<H3>");
this.writeOut(docSec.getSectionName());
this.writeOut("</H3>");
this.nl();
//Write the section
this.writeOut(docSec.getSectionContents());
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, writeSection()-HTMLOH");
} catch (Exception e) {
System.err.println("Nothing happened");
}
}
/**
* Write out entire file
* @param doc , document to write out
* @return boolean , whether or not operation was successful
*/
public boolean writeToDisk(Document doc) {
this.startFile();
this.startDocument(doc);
nettext.document.SectionList secList = doc.getSections();
for (int i = 0; i < secList.size(); i++) {
this.writeSection(secList.getSectionAt(i));
}
this.endDocument();
this.endFile();
this.cleanUp();
return true;
}
/*
* Helper Hunctions
*/
/**
* Helper function
* Writes the String toWrite to the stdOut
* @param toWrite , string to write out
* @throws IOException , throws excpetion if write was unsuccessfull
*/
private void writeOut(String toWrite) throws IOException {
oStream.print(toWrite);
oStream.flush();
}
/**
* Helper function
* Writes a newline to the file
* @throws IOException , throws excpetion if write was unsuccessfull
*/
private void nl() throws IOException {
//flush once for the bulk, twice for the left-overs
oStream.print("\n");
oStream.flush();
}
}

View File

@@ -0,0 +1,291 @@
package nettext.file;
import nettext.document.Document;
import nettext.document.DocumentSection;
import nettext.util.ContentProcessor;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import java.io.File;
/**
* This class is the NetText-format Document Reader which is used by
* DocumentReader to read-in NetText Documents.
*
* @author Jose Caban
*/
public class NetTextDocumentReader extends DefaultHandler {
/**
* This stores the Document to be read.
*/
private Document document;
/**
* Current Document Section being doing stuff to.
*/
private DocumentSection docSection;
/**
* The fileName of the File read in
*/
private String fileName;
/**
* Initialize the Document Reader Read through Repository and open
* streams for Documents.
*@param fileN file
* @return successful if true
*/
public boolean initialize(String fileN) {
this.fileName = fileN;
return true;
}
/**
* Read in a Document.
* @return Document a new Document as read in
*/
public Document readDocument() {
document = new Document();
//Do the parsing
SAXParserFactory factory = SAXParserFactory.newInstance();
File f = new File(fileName);
if (f == null) {
System.out.println("NetTextDocumentReader: Got a NULL for the file..."
+ " Can't read.");
System.out.flush();
return null;
} else if (XMLSettings.VERBOSE) {
System.out.println("DocumentReader: Reading from file:");
System.out.println("\t" + f.getAbsolutePath());
System.out.flush();
}
try {
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(f, this);
} catch (Exception exc) {
System.err.println("NetTextReader: Got an error:");
System.err.println("\t" + exc.getClass().getName() + ": "
+ exc.getMessage());
exc.printStackTrace();
return null;
}
document.setDocumentLoaded(true);
return document;
}
/**
* Processes the start of an XML element.
*
* @param uri a <code>String</code> value
* @param localName a <code>String</code> value
* @param qName a <code>String</code> value
* @param att an <code>Attributes</code> value
* @exception SAXException if an error occurs
*/
public void startElement(final String uri,
final String localName,
final String qName,
final Attributes att) throws SAXException {
if (XMLSettings.VERBOSE) {
System.out.println("NTDR: Got element start - " + qName);
System.out.flush();
}
String name = localName;
if (name == null || name.equals("")) {
name = qName;
}
//Grab in the case of a new Document
if (name.equals(XMLSettings.DOCUMENT_KEY)) {
/* - Variables - */
String docName = null; //hash the name to get the ID
String docID = null; //useless fellow, ID is just hash
String attributeName = null; //store the currently read attribute
//Loop through the variables
for (int i = 0; i < att.getLength(); i++) {
//get Current attribute
attributeName = att.getLocalName(i);
if (attributeName == null || attributeName.equals("")) {
attributeName = att.getQName(i);
}
//Check the current Attribute
if (attributeName.equals("name")) {
docName = att.getValue(i);
} else if (attributeName.equals("id")) {
docID = att.getValue(i);
} else {
System.err.println("NetTextDocReader: Unknown attribute: "
+ attributeName + "="
+ att.getValue(i));
}
}
//Ensure all (Required) Fields met
if (docName == null) {
System.err.println("NetTextDocReader: Could not read"
+ " Document. Syntax Error - document tag.");
System.err.flush();
this.document = null;
return;
}
this.document = new Document();
if (XMLSettings.VERBOSE) {
System.out.println("NTDR: Got document start - " + docName);
System.out.flush();
}
//Perform necessary actions with fields
this.document.setDocumentName(docName);
return;
} else if (name.equals(XMLSettings.DOCUMENT_SECTION)) {
//Grab a new Section
/* - Variables - */
String secName = null;
String secEditor = null;
String secTimeStamp = null;
String attributeName = null;
int secID = 0; //Because nothing is more zero
int secPosition = -1; //than -1
long parsedStamp = 0; //The parsed time stamp
//Loop through the variables
for (int i = 0; i < att.getLength(); i++) {
//get Current attribute
attributeName = att.getLocalName(i);
if (attributeName == null || attributeName.equals("")) {
attributeName = att.getQName(i);
}
//Check the current Attribute
if (attributeName.equals("name")) { //name
secName = att.getValue(i);
} else if (attributeName.equals("id")) { //id
secID = Integer.parseInt(att.getValue(i));
} else if (attributeName.equals("editor")) { //editor
secEditor = att.getValue(i);
} else if (attributeName.equals("position")) { //position
secPosition = Integer.parseInt(att.getValue(i));
} else if (attributeName.equals("time")) { //time
secTimeStamp = att.getValue(i);
} else { //else
System.err.println("NetTextDocReader: Unknown attribute: "
+ attributeName + "="
+ att.getValue(i));
}
}
//Ensure all (Required) Fields met
if (secName == null || secEditor == null || secTimeStamp == null
|| secPosition == -1 || secID == 0) {
System.err.println("NetTextDocReader: Could not read"
+ " Document. Syntax Error - section tag.");
this.document = null;
return;
}
try {
parsedStamp = Long.parseLong(secTimeStamp);
} catch (NumberFormatException nfe) {
System.out.println("NetTextDocumentReader: Got bad time stamp");
this.document = null;
return;
}
//Perform necessary actions with fields
this.docSection =
new DocumentSection(document.getDocumentId());
docSection.setSectionContents("");
docSection.setSectionId(secID);
docSection.setSectionName(secName);
docSection.setUserName(secEditor);
docSection.setTimeStamp(new java.util.Date(parsedStamp));
docSection.setSectionOrder(secPosition);
//Add the section to the document
document.addSection(docSection, docSection.getSectionOrder());
} else {
System.err.println("NetTextDocReader: Unknown attribute");
}
}
/**
* Processes string data within an XML element.
*
* @param ch a <code>char[]</code> value
* @param start an <code>int</code> value
* @param length an <code>int</code> value
*
*/
public void characters(char[] ch, int start, int length) {
if (docSection != null) {
//This looks a little odd, but there's no guarantee that the entire
//Section Contents will be sent at once.
String newString = docSection.getSectionContents()
+ new String(ch, start, length);
newString = ContentProcessor.getInstance().stripNewlines(newString);
newString = ContentProcessor.getInstance().literalsToTags(newString);
docSection.setSectionContents(newString);
}
}
/**
* Processes the end of an XML element.
*
* @param namespaceURI a <code>String</code> value
* @param localName a <code>String</code> value
* @param qName a <code>String</code> value
*
*/
public void endElement(String namespaceURI,
String localName, String qName) {
if (XMLSettings.VERBOSE) {
System.out.println("NTDR: Got element end - </" + qName + ">");
System.out.flush();
}
String name = localName;
if (name == null || name.equals("")) {
name = qName;
}
//Check if the Syntax is kept
if (docSection != null //Check the docSection closing
&& !name.equals(XMLSettings.DOCUMENT_SECTION)) {
System.out.println("NetTextReader: Unmatched closing Section tag..."
+ " " + name);
return;
} else if (docSection == null //Check the document closing
&& !name.equals(XMLSettings.DOCUMENT_KEY)) {
System.out.println("NetTextReader: Unmatched closing Document tag.."
+ " " + name);
return;
} else { //set docSection to null for prosperity
docSection = null;
return;
}
}
}

View File

@@ -0,0 +1,222 @@
package nettext.file;
import java.io.PrintWriter;
import java.io.IOException;
import nettext.document.Document;
import nettext.document.DocumentSection;
/*
* Removed for checkstyle
* import nettext.server.ServerUI;
*/
import nettext.server.ServerSettings;
import nettext.util.ContentProcessor;
/**
* This class defines the NetTextOutputHandler operations required by
* DocumentOutputHandlers.
*
* @author Jose Caban
*/
public class NetTextOutputHandler implements DocumentOutputHandler {
/**
* The Writer
*/
private java.io.PrintWriter oStream;
/**
* The Writee
*/
private String fileName;
/**
* Write out entire file
*@param doc document
*@return boolean
*/
public boolean writeToDisk(Document doc) {
String path = "";
path = ServerSettings.DEFAULT_REPOSITORY_LOCATION;
if (path.charAt(path.length() - 1) != '/') {
path += "/";
}
path += "doc" + Integer.toString(doc.getDocumentId()) + ".xml";
if (!this.initialize(path)) {
return false;
}
this.startFile();
this.startDocument(doc);
nettext.document.SectionList secList = doc.getSections();
for (int i = 0; i < secList.size(); i++) {
this.writeSection(secList.getSectionAt(i));
}
this.endDocument();
this.endFile();
this.cleanUp();
return true;
}
/**
* Standard Initialization function that initializes all fields
* to default values
*@param fileN filename
*@return boolean
*/
public boolean initialize(String fileN) {
if (fileN == null) {
return false;
}
this.fileName = fileN;
//initialize the PrintWriter
try {
oStream = new PrintWriter(new java.io.FileOutputStream(fileN));
} catch (IOException ioe) {
System.err.println("Error initializing Output Handler");
return false;
}
return true;
}
/**
* Flush/Close Buffers/Streams
*/
public void cleanUp() {
oStream.flush();
oStream.close();
}
/**
* Write the things at the start of the File
*/
public void startFile() {
try {
//Print out the start of the document.
this.writeOut("<?xml version='1.0'?>");
this.nl();
this.nl();
} catch (IOException ioe) {
System.err.println("IO EXCEPTION!!! BAD!!!!, startFile()-NTOH");
}
}
/**
* Write out the things related to ending the file
*/
public void endFile() {
}
/**
* Write out the things necessary to start the Document itself
*@param toWrite document
*
*/
public void startDocument(Document toWrite) {
try {
this.writeOut("<"
+ XMLSettings.DOCUMENT_KEY
+ " name=\""
+ toWrite.getDocumentName()
+ "\" id=\""
+ toWrite.getDocumentId()
+ "\">");
this.nl();
} catch (IOException ioe) {
System.err.println("IO Exception!! startDocument() - NTOH");
}
}
/**
* Write out the things necessary to close the Document
*/
public void endDocument() {
try {
this.writeOut("</" + XMLSettings.DOCUMENT_KEY + ">");
} catch (IOException ioe) {
System.err.println("IOException!! endDocument() - NTOH");
}
}
/**
* Write out a section of a given Document
* @param docSec a <code>DocumentSection</code> value
*/
public void writeSection(DocumentSection docSec) {
if (docSec == null) {
System.out.println("NTOH - why did you pass in a NULL?");
System.out.flush();
}
try {
//Write header info
this.writeOut("<"
+ XMLSettings.DOCUMENT_SECTION
+ " id=\""
+ docSec.getSectionId()
+ "\" name=\""
+ docSec.getSectionName()
+ "\" editor=\""
+ docSec.getUserName()
+ "\" time=\""
+ Long.toString(docSec.getTimeStamp().getTime())
+ "\" position=\""
+ Integer.toString(docSec.getSectionOrder())
+ "\">");
this.nl();
//write Section contents
this.writeOut(ContentProcessor.getInstance()
.tagsToLiterals(docSec.getSectionContents()));
this.nl();
//Close Section
this.writeOut("</" + XMLSettings.DOCUMENT_SECTION + ">");
this.nl();
} catch (IOException ioe) {
System.err.println("IOException!! writeSection - NTOH");
}
}
/*
* Helper Hunctions
*
*/
/**
* Helper function
* Writes the String toWrite to the stdOut
*@param toWrite string
*@throws IOException ioexception
*/
private void writeOut(String toWrite) throws IOException {
oStream.print(toWrite);
oStream.flush();
}
/**
* Helper function
* Writes a newline to the file
*@throws IOException ioexception
*/
private void nl() throws IOException {
//flush once for the bulk, twice for the left-overs
oStream.print("\n");
oStream.flush();
}
}

View File

@@ -0,0 +1,43 @@
package nettext.file;
/**
* Class XMLSettings: The XML Settings class contains some settings
* for the reading and writing of the XML save files.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the XMLSettings class
* </PRE>
*
* @author <A HREF="mailto:gtg184g@mail.gatech.edu">Jose Caban</A>
* @version Version 1.0, Feb. 20, 2004
*/
public class XMLSettings {
/**
* Debug output?
*/
public static final boolean VERBOSE = false;
/**
* The name of the root element of the Docuemnt XML.
*/
public static final String DOCUMENT_KEY = "document";
/**
* The name of the root element of the Document list XML
*/
public static final String DOCUMENT_LIST = "documents";
/**
* The name of the root element of a section
*/
public static final String DOCUMENT_SECTION = "section";
/**
* Creates a new <code>XMLSettings</code> instance.
*/
public XMLSettings() {
}
}

View File

@@ -0,0 +1,3 @@
<body>
Package description goes here.
</body>

View File

@@ -0,0 +1,54 @@
package nettext.messaging;
/**
* Class AbstractDocumentMessage: This class extends Abstract message
* and will be the parent class for all the Document Messages.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 25, 2004) - Created the AbstractDocumentMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@prism.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 25, 2004
*/
public abstract class AbstractDocumentMessage extends AbstractMessage {
/**
* This variable contains the documentId.
*
*/
private int documentId;
/**
* Creates a new <code>AbstractDocumentMessage</code> instance.

View File

@@ -0,0 +1,78 @@
package nettext.messaging;
import java.util.List;
import java.util.Vector;
/**
* Class AbstractListMessage: This class is the base for messages
* that will contain lists of documents and users. All of the more
* specific list classes will be derived from this class and will add
* the specialized functionality neccessary in each case.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the AbstractListMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg284h@prism.gatech.edu">Andrew Knight</A>
* @version Version 1.0, Feb. 20, 2004
*/
public abstract class AbstractListMessage extends AbstractMessage {
/**
* vecList is to hold a list of documents or a list of users
*/
private List vecList;
/**
* Creates a new <code>AbstractListMessage</code> instance.
*/
public AbstractListMessage() {
this(MessageSettings.UNKNOWN_TYPE);
}
/**
* Creates a new <code>AbstractListMessage</code> instance.
*
* @param type a <code>String</code> value
*/
public AbstractListMessage(final String type) {
this(type, null);
}
/**
* Creates a new <code></code> instance.
*
* @param type a <code>String</code> value
* @param author a <code>String</code> value
*/
public AbstractListMessage(final String type, final String author) {
super(type, author);
vecList = new Vector();
}
/**
* Accesses the size of the vecList
* @return int , represents the size of the vecList
*/
public int getSize() {
return vecList.size();
}
/**
* Accesses the vecList
* @param i , index of vecList that you want to access
* @return Object , element i of vecList
*/
public Object getVecList(int i) {
return vecList.get(i);
}
/**
* Add to the Vector list
* @param obj , object to add to list
*/
public void addToVecList(Object obj) {
this.vecList.add(obj);
}
}

View File

@@ -0,0 +1,149 @@
package nettext.messaging;
import java.util.List;
/**
* Class AbstractMessage: This class is the base for all network
* messages that will be sent between the client and the server. All
* of the more specific message classes will be derived from it and
* will add more and more spcific functionality onto the basics
* provided in this class.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 25, 2004) - Created the AbstractMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@prism.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 25, 2004
*/
public abstract class AbstractMessage {
/**
* This variable contains the four-character code for the message,
* like: HELO, or QUIT.
*/
private String messageType;
/**
* This string contains the name of the sender of this message,
* which will either be "Server" for server messages, or the name of
* the user for clients.
*/
private String messageAuthor;
/**
* Creates a new <code>AbstractMessage</code> instance.
*/
public AbstractMessage() {
this(MessageSettings.UNKNOWN_TYPE);
}
/**
* Creates a new <code>AbstractMessage</code> instance.
*
* @param type a <code>String</code> value
*/
public AbstractMessage(final String type) {
this(type, null);
}
/**
* Creates a new <code>AbstractMessage</code> instance.
*
* @param type a <code>String</code> value
* @param author a <code>String</code> value
*/
public AbstractMessage(final String type, final String author) {
messageType = type;
messageAuthor = author;
}
/**
* Returns the message type.
*
* @return a <code>String</code> value
*/
public final String getMessageType() {
return messageType;
}
/**
* Sets a new message type.
*
* @param newType a <code>String</code> value
*/
protected final void setMessageType(final String newType) {
this.messageType = newType;
}
/**
* Returns the message type of the message string passed in.
*
* @param message a <code>String</code> value
* @return a <code>String</code> value
*/
public static String getMessageType(final String message) {
if (message == null) {
return null;
}
if (message.length() < MessageSettings.TYPE_LENGTH) {
return null;
}
if (message.indexOf("\037".charAt(0)) != MessageSettings.TYPE_LENGTH) {
return null;
}
return message.substring(0, MessageSettings.TYPE_LENGTH);
}
/**
* Returns the name of the user that sent out the message.
*
* @return a <code>String</code> value
*/
public final String getAuthor() {
return messageAuthor;
}
/**
* Gives message author a new value.
*
* @param author a <code>String</code> value
*/
public final void setMessageAuthor(final String author) {
this.messageAuthor = author;
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public abstract String tokenize();
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
return null;
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
return null;
}
}

View File

@@ -0,0 +1,112 @@
package nettext.messaging;
import java.util.StringTokenizer;
/**
* Class AbstractServerMessage: This class extends Abstract Message
* and is the base for all server network messages.
* <PRE>
* Revision History:
* v1.0 (Jan. 29, 2004) - Created the AbstractServerMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@mail.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 29, 2004
*/
public abstract class AbstractServerMessage extends AbstractMessage {
/**
* This variable will conatin the String Message.
*/
private String serverMessage;
/**
* Creates a new <code>AbstractServerMessage</code> instance.
*
* @param type a <code>String</code> value
* @param incomingMessage a <code>String</code> value
*/
public AbstractServerMessage(final String type,
final String incomingMessage) {
super(type, MessageSettings.SERVER_USERNAME);
this.serverMessage = incomingMessage;
}
/**
* This is the accessor for serverMessage.
*
*@return server message
*/
public final String getServerMessage() {
return serverMessage;
}
/**
* This is a mutator for server message.
*
* @param newMessage a <code>String</code> value
*/
protected final void setServerMessage(final String newMessage) {
this.serverMessage = newMessage;
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public final String tokenize() {
return getMessageType()
+ "\037" + getAuthor()
+ "\037" + getServerMessage();
}
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
String type = getMessageType(message);
StringTokenizer st = null;
String temp = null;
if (type == null) {
return null;
}
if (!(type.equals(MessageSettings.SERVER_MESSAGE_TYPE)
|| type.equals(MessageSettings.SERVER_ERROR_TYPE))) {
return null;
}
st = new StringTokenizer(message, "\037");
//Message type:
if (!st.hasMoreTokens()) { return null; }
temp = st.nextToken();
//Author:
if (!st.hasMoreTokens()) { return null; }
temp = st.nextToken();
//Message:
if (!st.hasMoreTokens()) { return null; }
temp = st.nextToken();
if (type.equals(MessageSettings.SERVER_MESSAGE_TYPE)) {
return new GenericServerMessage(temp);
} else {
return new ServerErrorMessage(temp);
}
}
}

View File

@@ -0,0 +1,34 @@
package nettext.messaging;
/**
* Class AdministrativeMessage: This class extends Client Message and
* is the base for all administrative network messages that will be
* sent by the client. All of the more specific client message classes
* will be derived from it and will add more and more spcific
* functionality onto the basics provided in this class.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 29, 2004) - Created the AdministrativeMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@mail.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 29, 2004
*/
public abstract class AdministrativeMessage extends AbstractMessage {
/**
* Creates a new <code>AdministrativeMessage</code> instance.
*
* @param type a <code>String</code> value
* @param author a <code>String</code> value
*/
public AdministrativeMessage(final String type, final String author) {
super(type, author);
}
}

View File

@@ -0,0 +1,159 @@
package nettext.messaging;
import java.util.List;
import java.util.StringTokenizer;
/**
* Class ChatMessage: This class extends Client Message
* and is the base for all chat network messages.
* <PRE>
* Revision History:
* v1.0 (Jan. 29, 2004) - Created the ChatMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@mail.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 29, 2004
*/
public class ChatMessage extends AbstractMessage {
/**
* This is a variable that contains the chat message.
*/
private String message;
/**
* This is a variable that contains the document id.
*/
private int docId;
/**
* Creates a new <code>ChatMessage</code> instance.
* @param userName a <code>String</code> value
*/
public ChatMessage(final String userName) {
super(MessageSettings.CHAT_TYPE, userName);
docId = 0;
message = null;
}
/**
* This is the accessor for docId.
*
* @return docId.
*/
public final int getDocId() {
return this.docId;
}
/**
* This is the mutator for docId.
*
* @param newDocId a <code>String</code> value
*/
protected final void setDocId(final int newDocId) {
this.docId = newDocId;
}
/**
* This is the accessor for chatMessage.
*
* @return chat message
*/
public final String getChatMessage() {
return message;
}
/**
* This is a mutator for chat message.
*
* @param newMessage a <code>String</code> value
*/
protected final void setChatMessage(final String newMessage) {
this.message = newMessage;
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public final String tokenize() {
return getMessageType() + "\037" + getAuthor() + "\037"
+ Integer.toString(getDocId()) + "\037" + getChatMessage();
}
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
String type = getMessageType(message);
String usrName = null;
int id = 0;
String chatMessage = null;
StringTokenizer st = null;
ChatMessage result = null;
if (type == null) {
return null;
}
if (!type.equals(MessageSettings.CHAT_TYPE)) {
return null;
}
st = new StringTokenizer(message, "\037");
//Message Type
if (!st.hasMoreTokens()) { return null; }
type = st.nextToken();
//Username
if (!st.hasMoreTokens()) { return null; }
usrName = st.nextToken();
result = new ChatMessage(usrName);
//DocID
if (!st.hasMoreTokens()) {
return null;
}
try {
id = Integer.parseInt(st.nextToken());
} catch (NumberFormatException nfe) {
return null;
}
result.setDocId(id);
//Chat message
if (!st.hasMoreTokens()) { return null; }
chatMessage = st.nextToken();
result.setChatMessage(chatMessage);
return result;
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
if (data == null || (data.size() != 3)) {
return null;
}
ChatMessage result = new ChatMessage((String) (data.get(0)));
result.setDocId(((Integer) (data.get(1))).intValue());
result.setChatMessage((String) (data.get(2)));
return result;
}
}

View File

@@ -0,0 +1,155 @@
package nettext.messaging;
import java.util.List;
import java.util.StringTokenizer;
/**
* Class DeleteSectionMessage: This class is a message for
* removing a section from a document.
* <PRE>
* Revision History:
* v1.0 (Feb. 17, 2004) - Created the DeleteSectionMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@cc.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Feb. 17, 2004
*/
public class DeleteSectionMessage extends AbstractDocumentMessage {
/**
* This is a variable that contains the document id.
*/
private int docId;
/**
* int to hold the section ID # of the document of this message.
*/
private int iSecId;
/**
* Creates a new <code>DeleteSectionMessage</code> instance.
*
* @param userName a <code>String</code> value
*/
public DeleteSectionMessage(final String userName) {
super(MessageSettings.RM_SECT_TYPE, userName);
docId = 0;
iSecId = 0;
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
if (data == null || (data.size() != 3)) {
return null;
}
int i = 0;
DeleteSectionMessage result = null;
result = new DeleteSectionMessage((String) (data.get(i)));
result.setDocId(((Integer) data.get(++i)).intValue());
result.setSecId(((Integer) data.get(++i)).intValue());
return result;
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public final String tokenize() {
return getMessageType() + "\037" + getAuthor()
+ "\037" + Integer.toString(getDocId())
+ "\037" + Integer.toString(getSecId());
}
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
DeleteSectionMessage result = null;
String type = getMessageType(message);
StringTokenizer st = null;
if (type == null) {
return null;
}
if (!type.equals(MessageSettings.RM_SECT_TYPE)) {
return null;
}
st = new StringTokenizer(message, "\037");
//Message type:
if (!st.hasMoreTokens()) { return null; }
type = st.nextToken();
//Username:
if (!st.hasMoreTokens()) { return null; }
result = new DeleteSectionMessage(st.nextToken());
//DocumentID
if (!st.hasMoreTokens()) { return null; }
try {
result.setDocId(Integer.parseInt(st.nextToken()));
} catch (NumberFormatException nfe) {
return null;
}
//SectionID
if (!st.hasMoreTokens()) { return null; }
try {
result.setSecId(Integer.parseInt(st.nextToken()));
} catch (NumberFormatException nfe) {
return null;
}
return result;
}
/**
* Accessor for iSecId
* @return iSecId , The section id this messages refers to.
*/
public int getSecId() {
return this.iSecId;
}
/**
* Modifier for iSecId
* @param secId , Int value to set as SecId
*/
public void setSecId(int secId) {
this.iSecId = secId;
}
/**
* Get the value of documentId.
* @return value of documentId.
*/
public final int getDocumentId() {
return docId;
}
/**
* Set the value of documentId.
* @param v Value to assign to documentId.
*/
public final void setDocumentId(final int v) {
this.docId = v;
}
}

View File

@@ -0,0 +1,158 @@
package nettext.messaging;
import java.util.List;
import java.util.StringTokenizer;
import nettext.document.Document;
/**
* Class DocumentListMessage: This class of message will be used to send
* a list of documents that are on the server.
*
* <PRE>
* Revision History:
* v1.0 (Feb. 20, 2004) - Created the DocumentListMessage class
* </PRE>
*
* @author <A HREF="mailto:andrewk@cc.gatech.edu">Andrew Knight</A>
* @version Version 1.0, Feb. 20, 2004
*/
public class DocumentListMessage extends AbstractListMessage {
/**
* int to hold the number of documents this message is holding
*/
private int iDocCount;
/**
* Creates a new <code>DocumentListMessage</code> instance.
*/
public DocumentListMessage() {
super(MessageSettings.DOC_LIST_TYPE, "Server"); //no author param
iDocCount = 0;
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
if (data == null || (data.size() < 1)) {
return null;
}
int i = 0;
DocumentListMessage result = new DocumentListMessage();
//Number of documents
result.setDocCount(((Integer) data.get(i)).intValue());
//Adding all documents
if ((data.size() - 1) < (result.getDocCount())) { return null; }
for (int j = 0; j < result.getDocCount(); j++) {
result.addToVecList(data.get(++i));
}
return result;
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public final String tokenize() {
Document curDoc = null;
String message = getMessageType() + "\037"
+ Integer.toString(getSize());
//Adding all doument ids and document names to string
for (int i = 0; i < getSize(); i++) {
curDoc = (Document) getVecList(i);
// Document id #
message += "\037" + (new Integer(curDoc.getDocumentId())).toString();
// Document name
message += "\037" + curDoc.getDocumentName();
}
return message;
}
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
DocumentListMessage result = null;
String type = getMessageType(message);
StringTokenizer st = null;
String temp = null;
Document curDoc = null;
if (type == null) {
return null;
}
if (!type.equals(MessageSettings.DOC_LIST_TYPE)) {
return null;
}
st = new StringTokenizer(message, "\037");
//Message type:
if (!st.hasMoreTokens()) { return null; }
type = st.nextToken();
result = new DocumentListMessage();
//DocCount
if (!st.hasMoreTokens()) { return null; }
try {
result.setDocCount(Integer.parseInt(st.nextToken()));
} catch (NumberFormatException nfe) {
return null;
}
//Adding all documents
for (int i = 0; i < result.getDocCount(); i++) {
curDoc = new Document();
// Document ID #
if (!st.hasMoreTokens()) { return null; }
temp = st.nextToken();
// Document Name
if (!st.hasMoreTokens()) { return null; }
curDoc.setDocumentName(st.nextToken());
result.addToVecList(curDoc);
}
return result;
}
/**
* Accessor for iDocCount
* @return iDocCount , The amount of documents in the message.
*/
public int getDocCount() {
return this.iDocCount;
}
/**
* Modifier for iDocCount
* @param newDocCount , Int value to set iDocCount
*/
private void setDocCount(int newDocCount) {
this.iDocCount = newDocCount;
}
}

View File

@@ -0,0 +1,350 @@
package nettext.messaging;
import java.util.List;
import java.util.StringTokenizer;
import nettext.document.DocumentSection;
import nettext.document.SectionList;
import nettext.document.Document;
import java.util.Date;
/**
* Class DocumentMessage: This class is a message for
* transfering a document.
* <PRE>
* Revision History:
* v1.0 (Feb. 17, 2004) - Created the DocumentMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@cc.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Feb. 17, 2004
*/
public class DocumentMessage extends AbstractDocumentMessage {
/**
* A document for this message.
*/
private Document document;
/**
* Creates a new <code>DocumentMessage</code> instance.
*
*
*/
public DocumentMessage() {
super(MessageSettings.DOC_TRANSFER_TYPE, "");
document = new Document();
}
/**
* Accessor for Document
* @return docSection , The document that this message refers to.
*/
public Document getDocument() {
return this.document;
}
/**
* Modifier for Document
* @param doc ,value to set as doc
*/
public void setDocument(Document doc) {
this.document = doc;
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
if (data == null/* && (data.size() != 1)*/) {
return null;
}
DocumentMessage result = new DocumentMessage();
Document doc = ((Document) data.get(0));
result.setDocument(doc);
return result;
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public final String tokenize() {
Document doc = getDocument();
int count = doc.getSections().size();
String result = getMessageType();
SectionList sections = doc.getSections();
//docId
result += "\037" + Integer.toString(doc.getDocumentId());
//docName
result += "\037" + doc.getDocumentName();
if (!doc.isDocumentLoaded()) {
//if doc isn't loaded, that's it, ready to go
result += "\037" + "0";
return result;
} else {
result += "\037" + "1";
}
//keep going
//secCount
result += "\037" + Integer.toString(count);
//Tokenizing Sections
for (int i = 0; i < count; i++) {
DocumentSection docSection = null;
docSection = ((DocumentSection) (sections.get(i)));
//username
String userName = null;
//sectionId
int secId;
// The order in which the section appears in the document.
int sectionOrder;
//The date of the last edit, or when the section was locked.
Date timeStamp;
// string for lock
boolean lock = false;
String sectionLocked;
// Store the sectionName of this Section
String sectionName;
// The string with the contents of the section.
String sectionContents;
userName = docSection.getUserName();
secId = docSection.getSectionId();
sectionOrder = docSection.getSectionOrder();
timeStamp = docSection.getTimeStamp();
//sectionLocked
lock = docSection.isSectionLocked();
if (lock) {
sectionLocked = "1";
} else {
sectionLocked = "0";
}
sectionName = docSection.getSectionName();
sectionContents = docSection.getSectionContents();
//userName
result += "\037" + userName;
//secId
result += "\037" + Integer.toString(secId);
//sectionOrder
result += "\037" + Integer.toString(sectionOrder);
//timeStamp
result += "\037" + Long.toString(timeStamp.getTime());
//lock
result += "\037" + sectionLocked;
//SecName
result += "\037" + sectionName;
//secContents
result += "\037" + sectionContents;
}
return result;
}
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
DocumentMessage result = new DocumentMessage();
// Store the sections of this Document.
SectionList sections = null;
Document doc = new Document();
sections = doc.getSections();
String type = getMessageType(message);
String loadedFlag = "";
StringTokenizer st = null;
int count;
int docId;
if (type == null) {
return null;
}
if (!type.equals(MessageSettings.DOC_TRANSFER_TYPE)) {
return null;
}
st = new StringTokenizer(message, "\037");
//Message type:
if (!st.hasMoreTokens()) { return null; }
type = st.nextToken();
if (MessageSettings.VERBOSE) {
System.out.println("DocumentMessage: Got message type.");
System.out.flush();
}
//DocumentID
if (!st.hasMoreTokens()) { return null; }
try {
docId = Integer.parseInt(st.nextToken());
} catch (NumberFormatException nfe) {
return null;
}
if (MessageSettings.VERBOSE) {
System.out.println("DocumentMessage: Got document id.");
System.out.flush();
}
//DocName
if (!st.hasMoreTokens()) { return null; }
doc.setDocumentName(st.nextToken());
docId = doc.getDocumentId();
if (MessageSettings.VERBOSE) {
System.out.println("DocumentMessage: Got document name.");
System.out.flush();
}
//Check if it's loaded
if (!st.hasMoreTokens()) { return null; }
loadedFlag = st.nextToken();
//if not loaded "0"
if (loadedFlag.equals("0")) {
doc.setDocumentLoaded(false);
result.setDocument(doc);
return result;
} else {
//loaded
doc.setDocumentLoaded(true);
//secCount
if (!st.hasMoreTokens()) { return null; }
try {
count = Integer.parseInt(st.nextToken());
} catch (NumberFormatException nfe) {
return null;
}
if (MessageSettings.VERBOSE) {
System.out.println("DocumentMessage: Got section count.");
System.out.flush();
}
//Sections
for (int i = 0; i < count; i++) {
//new Section
DocumentSection docSec = new DocumentSection(docId);
//username
String userName = null;
//sectionId
int secId;
// The order in which the section appears in the document.
/*
*Removed for pmd
*int sectionOrder;
*/
//The date of the last edit, or when the section was locked.
/*
* Removed for pmd
* Date timeStamp;
*/
// string for lock
String sectionLocked;
// Store the sectionName of this Section
String sectionName;
// The string with the contents of the section.
String sectionContents;
//userName for section
if (!st.hasMoreTokens()) { return null; }
userName = st.nextToken();
docSec.setUserName(userName);
//secId
if (!st.hasMoreTokens()) {
return null;
}
try {
secId = Integer.parseInt(st.nextToken());
docSec.setSectionId(secId);
} catch (NumberFormatException nfe) {
return null;
}
//SecOrder
if (!st.hasMoreTokens()) { return null; }
try {
docSec.setSectionOrder(Integer.parseInt(st.nextToken()));
} catch (NumberFormatException nfe) {
return null;
}
//stamp
if (!st.hasMoreTokens()) { return null; }
try {
long temp = Long.parseLong(st.nextToken());
docSec.setTimeStamp(new Date(temp));
} catch (NumberFormatException pe) {
return null;
}
//locked
if (!st.hasMoreTokens()) { return null; }
sectionLocked = st.nextToken();
if (sectionLocked.equals("1")) {
docSec.lockSection();
} else {
docSec.unlockSection();
}
//secName
if (!st.hasMoreTokens()) { return null; }
sectionName = st.nextToken();
docSec.setSectionName(sectionName);
//secContents
if (!st.hasMoreTokens()) { return null; }
sectionContents = st.nextToken();
docSec.setSectionContents(sectionContents);
//add the section to the SectionList
sections.add(docSec);
} //for ends
result.setDocument(doc);
return result;
} //else for loaded
} //ends parse
} // end of class DocumentMessage

View File

@@ -0,0 +1,47 @@
package nettext.messaging;
import java.util.List;
/**
* Class GenericServerMessage: This is a generic server message.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 27, 2004) - Created the GenericServerMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@prism.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 29, 2004
*/
public class GenericServerMessage extends AbstractServerMessage {
/**
* Creates a new <code>GenericServerMessage</code> instance.
*
* @param message a <code>String</code> value
*/
public GenericServerMessage(final String message) {
super(MessageSettings.SERVER_MESSAGE_TYPE, message);
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
if (data == null || (data.size() != 1)) {
return null;
}
return new GenericServerMessage((String) (data.get(0)));
}
/**
* Makes a message from the data provided.
*/
protected void makeMessage() {
}
}

View File

@@ -0,0 +1,84 @@
package nettext.messaging;
import java.util.List;
import java.util.StringTokenizer;
/**
* Class JoinMessage: Sent by the client to the server when it wants
* to join the server.
*
* <PRE>
* Revision History:
* v1.0 (Jan. 27, 2004) - Created the JoinMessage class
* </PRE>
*
* @author <A HREF="mailto:gtg563g@mail.gatech.edu">Daniyar Zhanbekov</A>
* @version Version 1.0, Jan. 27, 2004
*/
public class JoinMessage extends AdministrativeMessage {
/**
* Creates a new <code>JoinMessage</code> instance.
*
* @param userName a <code>String</code> value
*/
public JoinMessage(final String userName) {
super(MessageSettings.JOIN_TYPE, userName);
}
/**
* Builds a message from the data provided.
*
* @param data a <code>List</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage buildMessage(final List data) {
if (data == null || (data.size() != 1)) {
return null;
}
String name = (String) (data.get(0));
return new JoinMessage(name);
}
/**
* Returns a string representation of the message fit for plain-text
* transmission over the network.
*
* @return a <code>String</code> value
*/
public final String tokenize() {
return getMessageType() + "\037" + getAuthor();
}
/**
* Parses the string into the specific message.
*
* @param message a <code>String</code> value
* @return an <code>AbstractMessage</code> value
*/
protected static AbstractMessage parse(final String message) {
String type = getMessageType(message);
StringTokenizer st = null;
if (type == null) {
return null;
}
if (!type.equals(MessageSettings.JOIN_TYPE)) {
return null;
}
st = new StringTokenizer(message, "\037");
//Message type:
if (!st.hasMoreTokens()) { return null; }
type = st.nextToken();
//Username:
if (!st.hasMoreTokens()) { return null; }
return new JoinMessage(st.nextToken());
}
}

Some files were not shown because too many files have changed in this diff Show More