зеркало из https://github.com/mozilla/gecko-dev.git
Removing this. It goes directly in mozilla/grendel because of classpath problems.
This commit is contained in:
Родитель
6790f2ffa5
Коммит
fde0b99211
|
@ -1,23 +0,0 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
dog \
|
||||
$(NULL)
|
||||
|
||||
include ../../rules.mk
|
|
@ -1,25 +0,0 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
nntp \
|
||||
util \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include ../../../../rules.mk
|
|
@ -1,400 +0,0 @@
|
|||
/*
|
||||
* Article.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.mail.nntp;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.activation.DataHandler;
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
|
||||
/**
|
||||
* The message class implementing the NNTP mail protocol.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 0.3
|
||||
*/
|
||||
public class Article extends MimeMessage {
|
||||
|
||||
/**
|
||||
* The unique message-id of this message.
|
||||
*/
|
||||
protected String messageId;
|
||||
|
||||
// Whether the headers for this article were retrieved using xover.
|
||||
boolean xoverHeaders = false;
|
||||
|
||||
/**
|
||||
* Creates an NNTP message with the specified article number.
|
||||
*/
|
||||
protected Article(Newsgroup folder, int msgnum) throws MessagingException {
|
||||
super(folder, msgnum);
|
||||
checkNewsrc(folder.newsrcline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NNTP message with the specified message-id.
|
||||
*/
|
||||
protected Article(Newsgroup folder, String messageId) throws MessagingException {
|
||||
super(folder, 0);
|
||||
this.messageId = messageId;
|
||||
checkNewsrc(folder.newsrcline);
|
||||
}
|
||||
|
||||
// Adds headers retrieved by an xover call to this article.
|
||||
void addXoverHeaders(InternetHeaders headers) {
|
||||
if (headers==null) {
|
||||
this.headers = headers;
|
||||
xoverHeaders = true;
|
||||
}
|
||||
}
|
||||
|
||||
void checkNewsrc(String newsrcline) throws MessagingException {
|
||||
if (newsrcline!=null) {
|
||||
int articlenum = getArticleNumber();
|
||||
StringTokenizer st = new StringTokenizer(newsrcline, ",");
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken();
|
||||
int hyphenIndex = token.indexOf('-');
|
||||
if (hyphenIndex>-1) { // range
|
||||
try {
|
||||
int lo = Integer.parseInt(token.substring(0, hyphenIndex));
|
||||
int hi = Integer.parseInt(token.substring(hyphenIndex+1));
|
||||
if (articlenum>=lo && articlenum<=hi) {
|
||||
setFlag(Flags.Flag.SEEN, true);
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
} else { // single number
|
||||
try {
|
||||
int num = Integer.parseInt(token);
|
||||
if (articlenum==num) {
|
||||
setFlag(Flags.Flag.SEEN, true);
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getArticleNumber() {
|
||||
return getMessageNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message content.
|
||||
*/
|
||||
public Object getContent() throws IOException, MessagingException {
|
||||
if (content==null) content = ((NNTPStore)folder.getStore()).getContent(this);
|
||||
|
||||
/*
|
||||
// check for embedded uuencoded content
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(ByteArrayInputStream(content)));
|
||||
Hashtable parts = null;
|
||||
try {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
int count = 1;
|
||||
for (String line = reader.readLine(); line!=null; line = reader.readLine()) {
|
||||
if (line.startsWith("begin")) {
|
||||
StringTokenizer st = new StringTokenizer(line, " ");
|
||||
if (st.countTokens()==3) {
|
||||
String ignore = st.nextToken();
|
||||
int lines = Integer.parseInt(st.nextToken());
|
||||
String name = st.nextToken();
|
||||
String contentType = guessContentType(name, count++);
|
||||
if (contentType!=null) {
|
||||
parts = new Hashtable();
|
||||
if (buffer.length>0) {
|
||||
parts.put("text/plain; partid="+(count++), buffer.toString());
|
||||
buffer = new StringBuffer();
|
||||
}
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
|
||||
}
|
||||
}
|
||||
} else
|
||||
buffer.append(line);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
*/
|
||||
return super.getContent();
|
||||
}
|
||||
|
||||
String guessContentType(String name, int count) {
|
||||
String lname = name.toLowerCase();
|
||||
if (lname.indexOf(".jpg")>-1 || lname.indexOf(".jpeg")>-1)
|
||||
return "image/jpeg; name=\""+name+"\", partid="+count;
|
||||
if (lname.indexOf(".gif")>-1)
|
||||
return "image/gif; name=\""+name+"\", partid="+count;
|
||||
if (lname.indexOf(".au")>-1)
|
||||
return "audio/basic; name=\""+name+"\", partid="+count;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the from address.
|
||||
*/
|
||||
public Address[] getFrom() throws MessagingException {
|
||||
NNTPStore s = (NNTPStore)folder.getStore();
|
||||
if (xoverHeaders && !s.validateOverviewHeader("From")) headers = null;
|
||||
if (headers==null) headers = s.getHeaders(this);
|
||||
|
||||
Address[] a = getAddressHeader("From");
|
||||
if (a==null) a = getAddressHeader("Sender");
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recipients' addresses for the specified RecipientType.
|
||||
*/
|
||||
public Address[] getRecipients(RecipientType type) throws MessagingException {
|
||||
NNTPStore s = (NNTPStore)folder.getStore();
|
||||
if (xoverHeaders && ! s.validateOverviewHeader(getHeaderKey(type))) headers = null;
|
||||
if (headers==null) headers = s.getHeaders(this);
|
||||
|
||||
if (type==RecipientType.NEWSGROUPS) {
|
||||
String key = getHeader("Newsgroups", ",");
|
||||
if (key==null) return null;
|
||||
return NewsAddress.parse(key);
|
||||
} else {
|
||||
return getAddressHeader(getHeaderKey(type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the recipients' addresses.
|
||||
*/
|
||||
public Address[] getAllRecipients() throws MessagingException {
|
||||
if (headers==null || xoverHeaders) headers = ((NNTPStore)folder.getStore()).getHeaders(this);
|
||||
|
||||
return super.getAllRecipients();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reply-to address.
|
||||
*/
|
||||
public Address[] getReplyTo() throws MessagingException {
|
||||
NNTPStore s = (NNTPStore)folder.getStore();
|
||||
if (xoverHeaders && !s.validateOverviewHeader("Reply-To")) headers = null;
|
||||
if (headers==null) headers = s.getHeaders(this);
|
||||
|
||||
Address[] a = getAddressHeader("Reply-To");
|
||||
if (a==null) a = getFrom();
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subject line.
|
||||
*/
|
||||
public String getSubject() throws MessagingException {
|
||||
NNTPStore s = (NNTPStore)folder.getStore();
|
||||
if (xoverHeaders && !s.validateOverviewHeader("Subject")) headers = null;
|
||||
if (headers==null) headers = s.getHeaders(this);
|
||||
|
||||
return super.getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sent date.
|
||||
*/
|
||||
public Date getSentDate() throws MessagingException {
|
||||
NNTPStore s = (NNTPStore)folder.getStore();
|
||||
if (xoverHeaders && !s.validateOverviewHeader("Date")) headers = null;
|
||||
if (headers==null) headers = s.getHeaders(this);
|
||||
|
||||
return super.getSentDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the received date.
|
||||
*/
|
||||
public Date getReceivedDate() throws MessagingException {
|
||||
if (headers==null || xoverHeaders) headers = ((NNTPStore)folder.getStore()).getHeaders(this);
|
||||
|
||||
return super.getReceivedDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of addresses for the specified header key.
|
||||
*/
|
||||
protected Address[] getAddressHeader(String key) throws MessagingException {
|
||||
String header = getHeader(key, ",");
|
||||
if (header==null) return null;
|
||||
try {
|
||||
return InternetAddress.parse(header);
|
||||
} catch (AddressException e) {
|
||||
String message = e.getMessage();
|
||||
if (message!=null && message.indexOf("@domain")>-1)
|
||||
try {
|
||||
return parseAddress(header, ((NNTPStore)folder.getStore()).getHostName());
|
||||
} catch (AddressException e2) {
|
||||
throw new MessagingException("Invalid address: "+header, e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a pass at parsing internet addresses.
|
||||
*/
|
||||
protected Address[] parseAddress(String in, String defhost) throws AddressException {
|
||||
Vector v = new Vector();
|
||||
for (StringTokenizer st = new StringTokenizer(in, ","); st.hasMoreTokens(); ) {
|
||||
String s = st.nextToken().trim();
|
||||
try {
|
||||
v.addElement(new InternetAddress(s));
|
||||
} catch (AddressException e) {
|
||||
int index = s.indexOf('>');
|
||||
if (index>-1) { // name <address>
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(s.substring(0, index));
|
||||
buffer.append('@');
|
||||
buffer.append(defhost);
|
||||
buffer.append(s.substring(index));
|
||||
v.addElement(new InternetAddress(buffer.toString()));
|
||||
} else {
|
||||
index = s.indexOf(" (");
|
||||
if (index>-1) { // address (name)
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(s.substring(0, index));
|
||||
buffer.append('@');
|
||||
buffer.append(defhost);
|
||||
buffer.append(s.substring(index));
|
||||
v.addElement(new InternetAddress(buffer.toString()));
|
||||
} else // address
|
||||
v.addElement(new InternetAddress(s+"@"+defhost));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Address[] a = new Address[v.size()]; v.copyInto(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header key for the specified RecipientType.
|
||||
*/
|
||||
protected String getHeaderKey(RecipientType type) throws MessagingException {
|
||||
if (type==RecipientType.TO)
|
||||
return "To";
|
||||
if (type==RecipientType.CC)
|
||||
return "Cc";
|
||||
if (type==RecipientType.BCC)
|
||||
return "Bcc";
|
||||
if (type==RecipientType.NEWSGROUPS)
|
||||
return "Newsgroups";
|
||||
throw new MessagingException("Invalid recipient type: "+type);
|
||||
}
|
||||
|
||||
// -- Need to override these since we are read-only --
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setFrom(Address address) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void addFrom(Address a[]) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setRecipients(javax.mail.Message.RecipientType recipienttype, Address a[]) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void addRecipients(javax.mail.Message.RecipientType recipienttype, Address a[]) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setReplyTo(Address a[]) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setSubject(String s, String s1) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setSentDate(Date date) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setDisposition(String s) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setContentID(String s) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setContentMD5(String s) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setDescription(String s, String s1) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP messages are read-only.
|
||||
*/
|
||||
public void setDataHandler(DataHandler datahandler) throws MessagingException {
|
||||
throw new IllegalWriteException("Article is read-only");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
$(NULL)
|
||||
|
||||
SRCS= \
|
||||
Article.java \
|
||||
Newsgroup.java \
|
||||
NNTPStore.java \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include ../../../../../rules.mk
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* Newsgroup.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.mail.nntp;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.mail.*;
|
||||
import javax.mail.event.*;
|
||||
|
||||
/**
|
||||
* The folder class implementing the NNTP mail protocol.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 0.3
|
||||
*/
|
||||
public class Newsgroup extends Folder {
|
||||
|
||||
String name;
|
||||
int count = -1;
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
boolean postingAllowed = false;
|
||||
boolean subscribed = false;
|
||||
String newsrcline;
|
||||
|
||||
boolean open = false;
|
||||
|
||||
Article[] articles;
|
||||
Date checkpoint;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected Newsgroup(Store store, String name) {
|
||||
super(store);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
protected Newsgroup(Store store, String name, int count, int first, int last) {
|
||||
super(store);
|
||||
this.name = name;
|
||||
this.count = count;
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this folder.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name of this folder.
|
||||
*/
|
||||
public String getFullName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this folder.
|
||||
*/
|
||||
public int getType() throws MessagingException {
|
||||
return HOLDS_MESSAGES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this folder exists.
|
||||
*/
|
||||
public boolean exists() throws MessagingException {
|
||||
if (open) return true;
|
||||
try {
|
||||
open(READ_ONLY);
|
||||
close(false);
|
||||
return true;
|
||||
} catch (MessagingException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this folder contains any new articles.
|
||||
*/
|
||||
public boolean hasNewMessages() throws MessagingException {
|
||||
return getNewMessageCount()>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens this folder.
|
||||
*/
|
||||
public void open(int mode) throws MessagingException {
|
||||
if (open)
|
||||
throw new MessagingException("Newsgroup is already open");
|
||||
if (mode!=READ_ONLY)
|
||||
throw new MessagingException("Newsgroup is read-only");
|
||||
((NNTPStore)store).open(this);
|
||||
open = true;
|
||||
notifyConnectionListeners(ConnectionEvent.OPENED);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this folder.
|
||||
*/
|
||||
public void close(boolean expunge) throws MessagingException {
|
||||
if (!open)
|
||||
throw new MessagingException("Newsgroup is not open");
|
||||
if (expunge) expunge();
|
||||
((NNTPStore)store).close(this);
|
||||
open = false;
|
||||
notifyConnectionListeners(ConnectionEvent.CLOSED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expunges this folder.
|
||||
*/
|
||||
public Message[] expunge() throws MessagingException {
|
||||
throw new MessagingException("Newsgroup is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this folder is open.
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this folder is subscribed.
|
||||
*/
|
||||
public boolean isSubscribed() {
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the permanent flags for this folder.
|
||||
*/
|
||||
public Flags getPermanentFlags() { return new Flags(); }
|
||||
|
||||
/**
|
||||
* Returns the number of articles in this folder.
|
||||
*/
|
||||
public int getMessageCount() throws MessagingException {
|
||||
return getMessages().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the articles in this folder.
|
||||
*/
|
||||
public Message[] getMessages() throws MessagingException {
|
||||
if (!open)
|
||||
throw new MessagingException("Newsgroup is not open");
|
||||
NNTPStore s = (NNTPStore)store;
|
||||
if (articles==null)
|
||||
articles = s.getArticles(this);
|
||||
else { // check for new articles
|
||||
Article[] nm = s.getNewArticles(this, checkpoint);
|
||||
if (nm.length>0) {
|
||||
Article[] m2 = new Article[articles.length+nm.length];
|
||||
System.arraycopy(articles, 0, m2, 0, articles.length);
|
||||
System.arraycopy(nm, 0, m2, articles.length, nm.length);
|
||||
articles = m2;
|
||||
}
|
||||
}
|
||||
checkpoint = new Date();
|
||||
return articles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified article in this folder.
|
||||
* Since NNTP articles are not stored in sequential order,
|
||||
* the effect is just to reference articles returned by getMessages().
|
||||
*/
|
||||
public Message getMessage(int msgnum) throws MessagingException {
|
||||
return getMessages()[msgnum-1];
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders are read-only.
|
||||
*/
|
||||
public void appendMessages(Message articles[]) throws MessagingException {
|
||||
throw new MessagingException("Folder is read-only");
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public void fetch(Message articles[], FetchProfile fetchprofile) throws MessagingException {
|
||||
}
|
||||
|
||||
// -- These must be overridden to throw exceptions --
|
||||
|
||||
/**
|
||||
* NNTP folders can't have parents.
|
||||
*/
|
||||
public Folder getParent() throws MessagingException {
|
||||
throw new MessagingException("Newsgroup can't have a parent");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders can't contain subfolders.
|
||||
*/
|
||||
public Folder[] list(String s) throws MessagingException {
|
||||
throw new MessagingException("Newsgroups can't contain subfolders");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders can't contain subfolders.
|
||||
*/
|
||||
public Folder getFolder(String s) throws MessagingException {
|
||||
throw new MessagingException("Newsgroups can't contain subfolders");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders can't contain subfolders.
|
||||
*/
|
||||
public char getSeparator() throws MessagingException {
|
||||
throw new MessagingException("Newsgroups can't contain subfolders");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders can't be created, deleted, or renamed.
|
||||
*/
|
||||
public boolean create(int i) throws MessagingException {
|
||||
throw new MessagingException("Newsgroups can't be created");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders can't be created, deleted, or renamed.
|
||||
*/
|
||||
public boolean delete(boolean flag) throws MessagingException {
|
||||
throw new MessagingException("Newsgroups can't be deleted");
|
||||
}
|
||||
|
||||
/**
|
||||
* NNTP folders can't be created, deleted, or renamed.
|
||||
*/
|
||||
public boolean renameTo(Folder folder) throws MessagingException {
|
||||
throw new MessagingException("Newsgroups can't be renamed");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* CRLFInputStream.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.mail.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* An input stream that filters out CR/LF pairs into LFs.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 0.1
|
||||
*/
|
||||
public class CRLFInputStream extends PushbackInputStream {
|
||||
|
||||
/**
|
||||
* The CR octet.
|
||||
*/
|
||||
public static final int CR = 13;
|
||||
|
||||
/**
|
||||
* The LF octet.
|
||||
*/
|
||||
public static final int LF = 10;
|
||||
|
||||
/**
|
||||
* Constructs a CR/LF input stream connected to the specified input stream.
|
||||
*/
|
||||
public CRLFInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this input stream.
|
||||
* Returns -1 if the end of the stream has been reached.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
int c = super.read();
|
||||
if (c==CR) // skip CR
|
||||
return super.read();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to b.length bytes of data from this input stream into
|
||||
* an array of bytes.
|
||||
* Returns -1 if the end of the stream has been reached.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from this input stream into an
|
||||
* array of bytes, starting at the specified offset.
|
||||
* Returns -1 if the end of the stream has been reached.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int l = super.read(b, off, len);
|
||||
return removeCRs(b, off, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line of input terminated by LF.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public String readLine() throws IOException {
|
||||
byte[] acc = new byte[4096];
|
||||
int count = 0;
|
||||
for (byte b=(byte)read(); b!=LF && b!=-1; b=(byte)read())
|
||||
acc[count++] = b;
|
||||
if (count>0) {
|
||||
byte[] bytes = new byte[count];
|
||||
System.arraycopy(acc, 0, bytes, 0, count);
|
||||
return new String(bytes);
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
int removeCRs(byte[] b, int off, int len) {
|
||||
for (int index = indexOfCR(b, off, len); index>-1; index = indexOfCR(b, off, len)) {
|
||||
for (int i=index; i<b.length-1; i++)
|
||||
b[i] = b[i+1];
|
||||
len--;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int indexOfCR(byte[] b, int off, int len) {
|
||||
for (int i=off; i<off+len; i++)
|
||||
if (b[i]==CR) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* CRLFOutputStream.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.mail.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* An output stream that filters LFs into CR/LF pairs.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 0.1
|
||||
*/
|
||||
public class CRLFOutputStream extends FilterOutputStream {
|
||||
|
||||
/**
|
||||
* The CR octet.
|
||||
*/
|
||||
public static final int CR = 13;
|
||||
|
||||
/**
|
||||
* The LF octet.
|
||||
*/
|
||||
public static final int LF = 10;
|
||||
|
||||
/**
|
||||
* The CR/LF pair.
|
||||
*/
|
||||
public static final byte[] CRLF = { CR, LF };
|
||||
|
||||
/**
|
||||
* The last byte read.
|
||||
*/
|
||||
protected int last;
|
||||
|
||||
/**
|
||||
* Constructs a CR/LF output stream connected to the specified output stream.
|
||||
*/
|
||||
public CRLFOutputStream(OutputStream out) {
|
||||
super(out);
|
||||
last = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character to the underlying stream.
|
||||
* @exception IOException if an I/O error occurred
|
||||
*/
|
||||
public void write(int ch) throws IOException {
|
||||
if (ch==CR)
|
||||
out.write(CRLF);
|
||||
else
|
||||
if (ch==LF) {
|
||||
if (last!=CR)
|
||||
out.write(CRLF);
|
||||
} else {
|
||||
out.write(ch);
|
||||
}
|
||||
last = ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array to the underlying stream.
|
||||
* @exception IOException if an I/O error occurred
|
||||
*/
|
||||
public void write(byte b[]) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a portion of a byte array to the underlying stream.
|
||||
* @exception IOException if an I/O error occurred
|
||||
*/
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
int d = off;
|
||||
len += off;
|
||||
for (int i=off; i<len; i++)
|
||||
switch (b[i]) {
|
||||
default:
|
||||
break;
|
||||
case CR:
|
||||
if (i+1<len && b[i+1]==LF) {
|
||||
i++;
|
||||
} else {
|
||||
out.write(b, d, (i-d)+1);
|
||||
out.write(LF);
|
||||
d = i+1;
|
||||
}
|
||||
break;
|
||||
case LF:
|
||||
out.write(b, d, i-d);
|
||||
out.write(CRLF, 0, 2);
|
||||
d = i+1;
|
||||
break;
|
||||
}
|
||||
if (len-d>0)
|
||||
out.write(b, d, len-d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a newline to the underlying stream.
|
||||
* @exception IOException if an I/O error occurred
|
||||
*/
|
||||
public void writeln() throws IOException {
|
||||
out.write(CRLF);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
$(NULL)
|
||||
|
||||
SRCS= \
|
||||
CRLFInputStream.java \
|
||||
CRLFOutputStream.java \
|
||||
MessageInputStream.java \
|
||||
MessageOutputStream.java \
|
||||
$(NULL)
|
||||
|
||||
include ../../../../../rules.mk
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* MessageInputStream.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.mail.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A utility class for feeding message contents to messages.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 0.1
|
||||
*/
|
||||
public class MessageInputStream extends FilterInputStream {
|
||||
|
||||
/**
|
||||
* The stream termination octet.
|
||||
*/
|
||||
public static final int END = 46;
|
||||
|
||||
/**
|
||||
* The line termination octet.
|
||||
*/
|
||||
public static final int LF = 10;
|
||||
|
||||
boolean done = false;
|
||||
int last = -1; // register for the last octet read
|
||||
|
||||
/**
|
||||
* Constructs a message input stream connected to the specified pushback input stream.
|
||||
*/
|
||||
public MessageInputStream(PushbackInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this message input stream.
|
||||
* Returns -1 if the end of the message stream has been reached.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
if (done) return -1;
|
||||
int ch = in.read();
|
||||
if (ch==END && last==LF) {
|
||||
int ch2 = in.read(); // look ahead for LF
|
||||
if (ch2==LF) {
|
||||
done = true;
|
||||
return -1; // swallow the END and LF
|
||||
} else
|
||||
((PushbackInputStream)in).unread(ch2);
|
||||
}
|
||||
last = ch;
|
||||
return ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to b.length bytes of data from this input stream into
|
||||
* an array of bytes.
|
||||
* Returns -1 if the end of the stream has been reached.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from this input stream into an
|
||||
* array of bytes, starting at the specified offset.
|
||||
* Returns -1 if the end of the stream has been reached.
|
||||
* @exception IOException if an I/O error occurs
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (done) return -1;
|
||||
int l = in.read(b, off, len);
|
||||
int i = indexOfEnd(b, off, l);
|
||||
if (i>-1) {
|
||||
((PushbackInputStream)in).unread(b, i+2, (l-(off+i+2)));
|
||||
done = true;
|
||||
return i-off;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
// Discover the index of END in a byte array.
|
||||
int indexOfEnd(byte[] b, int off, int len) {
|
||||
for (int i=off+2; i<(off+len); i++)
|
||||
if (b[i]==LF && b[i-1]==END && b[i-2]==LF)
|
||||
return i-1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* MessageOutputStream.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.mail.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* An output stream that escapes any dots on a line by themself with
|
||||
* another dot, for the purposes of sending messages to SMTP and NNTP servers.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 0.1
|
||||
*/
|
||||
public class MessageOutputStream extends FilterOutputStream {
|
||||
|
||||
/**
|
||||
* The stream termination octet.
|
||||
*/
|
||||
public static final int END = 46;
|
||||
|
||||
/**
|
||||
* The line termination octet.
|
||||
*/
|
||||
public static final int LF = 10;
|
||||
|
||||
int last = -1; // the last character written to the stream
|
||||
|
||||
/**
|
||||
* Constructs a message output stream connected to the specified output stream.
|
||||
* @param out the target output stream
|
||||
*/
|
||||
public MessageOutputStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a character to the underlying stream.
|
||||
* @exception IOException if an I/O error occurred
|
||||
*/
|
||||
public void write(int ch) throws IOException {
|
||||
if ((last==LF || last==-1) && ch==END)
|
||||
out.write(END); // double any lonesome dots
|
||||
super.write(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a portion of a byte array to the underlying stream.
|
||||
* @exception IOException if an I/O error occurred
|
||||
*/
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
int k = last != -1 ? last : LF;
|
||||
int l = off;
|
||||
len += off;
|
||||
for (int i = off; i < len; i++) {
|
||||
if (k==LF && b[i]==END) {
|
||||
super.write(b, l, i-l);
|
||||
out.write(END);
|
||||
l = i;
|
||||
}
|
||||
k = b[i];
|
||||
}
|
||||
if (len-l > 0)
|
||||
super.write(b, l, len-l);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.0 (the "License"); you may not use this file except in
|
||||
# compliance with the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
$(NULL)
|
||||
|
||||
SRCS= \
|
||||
ObjectCollator.java \
|
||||
Referential.java \
|
||||
StatusEvent.java \
|
||||
StatusListener.java \
|
||||
StatusSource.java \
|
||||
Timer.java \
|
||||
TimerEvent.java \
|
||||
TimerListener.java \
|
||||
Tree.java \
|
||||
TreeCollator.java \
|
||||
TreeEvent.java \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include ../../../../rules.mk
|
|
@ -1,288 +0,0 @@
|
|||
/*
|
||||
* ObjectCollator.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A class for comparing objects in a tree.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public class ObjectCollator extends Collator {
|
||||
|
||||
protected Collator collator;
|
||||
|
||||
protected boolean descending = false;
|
||||
|
||||
/**
|
||||
* Constructs a ObjectCollator for the default locale.
|
||||
*/
|
||||
public ObjectCollator() {
|
||||
collator = Collator.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ObjectCollator for the specified locale.
|
||||
*/
|
||||
public ObjectCollator(Locale locale) {
|
||||
collator = Collator.getInstance(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this collator returns the opposite of any comparison.
|
||||
* @see #setDescending
|
||||
*/
|
||||
public boolean isDescending() { return descending; }
|
||||
|
||||
/**
|
||||
* Sets whether this collator returns the opposite of any comparison.
|
||||
* @param descending true if this collator returns the opposite of any comparison, false otherwise
|
||||
* @see #setDescending
|
||||
*/
|
||||
public void setDescending(boolean descending) { this.descending = descending; }
|
||||
|
||||
/**
|
||||
* Utility method to return the opposite of a comparison if descending is true.
|
||||
*/
|
||||
protected int applyDescending(int comparison) {
|
||||
return (!descending ? comparison : -comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to return the opposite of a comparison if descending is true.
|
||||
*/
|
||||
protected int applyDescending(double comparison) {
|
||||
return (!descending ? (int)Math.rint(comparison) : (int)Math.rint(comparison*(-1.0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the source string to the target string according to the collation rules for this Collator.
|
||||
* Returns an integer less than, equal to or greater than zero depending on whether the source String
|
||||
* is less than, equal to or greater than the target string.
|
||||
* @param source the source string.
|
||||
* @param target the target string.
|
||||
* @see java.text.CollationKey
|
||||
*/
|
||||
public int compare(String source, String target) {
|
||||
return applyDescending(collator.compare(source, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the source object to the target object according to the collation rules for this Collator.
|
||||
* Returns an integer less than, equal to or greater than zero depending on whether the source object
|
||||
* is less than, equal to or greater than the target object.
|
||||
* Objects that can validly be compared by such means include:<ul>
|
||||
* <li>Boolean - false is less than true, can only be compared with another Boolean
|
||||
* <li>Byte
|
||||
* <li>Date - before is less than after, can only be compared with another Date
|
||||
* <li>Double
|
||||
* <li>Float
|
||||
* <li>Long
|
||||
* <li>Integer
|
||||
* <li>Short
|
||||
* <li>String
|
||||
* @param source the source object.
|
||||
* @param target the target object.
|
||||
*/
|
||||
public int compare(Object source, Object target) {
|
||||
if (source instanceof String) {
|
||||
if (target instanceof String)
|
||||
return applyDescending(collator.compare((String)source, (String)target));
|
||||
else if (target instanceof Number)
|
||||
return applyDescending(collator.compare((String)source, target.toString()));
|
||||
} else if (source instanceof Integer) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending(((Number)target).intValue()-((Integer)source).intValue());
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Double) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((double)(((Number)target).doubleValue()-((Double)source).doubleValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Long) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).longValue()-((Long)source).longValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Float) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((double)(((Number)target).floatValue()-((Float)source).floatValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Byte) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).byteValue()-((Byte)source).byteValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Short) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).shortValue()-((Short)source).shortValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Boolean) {
|
||||
if (target instanceof Boolean) {
|
||||
boolean s = ((Boolean)source).booleanValue(), t = ((Boolean)target).booleanValue();
|
||||
if (!s && t) return applyDescending(-1); else if (s && !t) return applyDescending(1);
|
||||
}
|
||||
} else if (source instanceof Date) {
|
||||
if (target instanceof Date) {
|
||||
Date s = (Date)source, t = (Date)target;
|
||||
if (s.before(t)) return applyDescending(-1); else if (s.after(t)) return applyDescending(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the String into a series of bits that can be compared bitwise to other CollationKeys.
|
||||
* CollationKeys provide better performance than Collator.compare when Strings are involved in multiple comparisons.
|
||||
* @param source the string to be transformed into a collation key.
|
||||
* @return the CollationKey for the given String based on this Collator's collation rules. If the source String is null, a null CollationKey is returned.
|
||||
* @see java.text.CollationKey
|
||||
* @see #compare
|
||||
*/
|
||||
public CollationKey getCollationKey(String source) {
|
||||
return collator.getCollationKey(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for comparing the equality of two strings based on this Collator's collation rules.
|
||||
* @param source the source string to be compared with.
|
||||
* @param target the target string to be compared with.
|
||||
* @return true if the strings are equal according to the collation rules, false otherwise.
|
||||
* @see #compare
|
||||
*/
|
||||
public boolean equals(String source, String target) {
|
||||
return collator.equals(source, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this Collator's strength property.
|
||||
* The strength property determines the minimum level of difference considered significant during comparison.
|
||||
* See the Collator class description for an example of use.
|
||||
* @return this Collator's current strength property.
|
||||
* @see #setStrength
|
||||
*/
|
||||
public int getStrength() { return collator.getStrength(); }
|
||||
|
||||
/**
|
||||
* Sets this Collator's strength property.
|
||||
* The strength property determines the minimum level of difference considered significant during comparison.
|
||||
* See the Collator class description for an example of use.
|
||||
* @param newStrength the new strength value.
|
||||
* @exception IllegalArgumentException if the new strength value is not one of PRIMARY, SECONDARY, TERTIARY or IDENTICAL.
|
||||
* @see #getStrength
|
||||
*/
|
||||
public void setStrength(int newStrength) { collator.setStrength(newStrength); }
|
||||
|
||||
/**
|
||||
* Get the decomposition mode of this Collator.
|
||||
* Decomposition mode determines how Unicode composed characters are handled.
|
||||
* Adjusting decomposition mode allows the user to select between faster and more complete collation behavior.
|
||||
* The three values for decomposition mode are: <ul>
|
||||
* <li>NO_DECOMPOSITION,
|
||||
* <li>CANONICAL_DECOMPOSITION
|
||||
* <li>FULL_DECOMPOSITION.
|
||||
* </ul>See the documentation for these three constants for a description of their meaning.
|
||||
* @return the decomposition mode
|
||||
* @see #setDecomposition
|
||||
*/
|
||||
public int getDecomposition() { return collator.getDecomposition(); }
|
||||
|
||||
/**
|
||||
* Set the decomposition mode of this Collator.
|
||||
* See getDecomposition for a description of decomposition mode.
|
||||
* @param decompositionMode the new decomposition mode
|
||||
* @throws IllegalArgumentException if the given value is not a valid decomposition mode.
|
||||
* @see #getDecomposition
|
||||
*/
|
||||
public void setDecomposition(int decompositionMode) { collator.setDecomposition(decompositionMode); }
|
||||
|
||||
public int hashCode() { return collator.hashCode(); }
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof ObjectCollator) {
|
||||
ObjectCollator oc = (ObjectCollator)other;
|
||||
return (collator.equals(oc.collator));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a string description of this object.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(getClass().getName());
|
||||
buffer.append("[");
|
||||
buffer.append(paramString().toString());
|
||||
buffer.append("]");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
protected StringBuffer paramString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("strength=");
|
||||
switch (getStrength()) {
|
||||
case PRIMARY:
|
||||
buffer.append("PRIMARY");
|
||||
break;
|
||||
case SECONDARY:
|
||||
buffer.append("SECONDARY");
|
||||
break;
|
||||
case TERTIARY:
|
||||
buffer.append("TERTIARY");
|
||||
break;
|
||||
case IDENTICAL:
|
||||
buffer.append("IDENTICAL");
|
||||
break;
|
||||
default:
|
||||
buffer.append("unknown");
|
||||
}
|
||||
buffer.append(",decomposition=");
|
||||
switch (getDecomposition()) {
|
||||
case NO_DECOMPOSITION:
|
||||
buffer.append("NO_DECOMPOSITION");
|
||||
break;
|
||||
case CANONICAL_DECOMPOSITION:
|
||||
buffer.append("CANONICAL_DECOMPOSITION");
|
||||
break;
|
||||
case FULL_DECOMPOSITION:
|
||||
buffer.append("FULL_DECOMPOSITION");
|
||||
break;
|
||||
default:
|
||||
buffer.append("unknown");
|
||||
}
|
||||
if (descending) buffer.append(",descending");
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Referential.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
/**
|
||||
* An interface implemented by objects that maintain an external object reference.
|
||||
* <p>
|
||||
* This reference can be used to tag objects with a datasource id or store a hashtable of associated values.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public interface Referential {
|
||||
|
||||
/**
|
||||
* Returns the object reference.
|
||||
*/
|
||||
public Object getReference();
|
||||
|
||||
/**
|
||||
* Sets the object reference.
|
||||
* @param reference the object reference to store.
|
||||
*/
|
||||
public void setReference(Object reference);
|
||||
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* StatusEvent.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A status message.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public class StatusEvent extends EventObject {
|
||||
|
||||
public static final int OPERATION_START = 0;
|
||||
|
||||
public static final int OPERATION_UPDATE = 1;
|
||||
|
||||
public static final int OPERATION_END = 2;
|
||||
|
||||
public static final int UNKNOWN = -1;
|
||||
|
||||
protected int type;
|
||||
|
||||
protected String operation;
|
||||
|
||||
protected int minimum = UNKNOWN;
|
||||
|
||||
protected int maximum = UNKNOWN;
|
||||
|
||||
protected int value = UNKNOWN;
|
||||
|
||||
/**
|
||||
* Creates a new status event with the specified type and operation.
|
||||
*/
|
||||
public StatusEvent(Object source, int type, String operation) {
|
||||
super(source);
|
||||
switch (type) {
|
||||
case OPERATION_START:
|
||||
case OPERATION_UPDATE:
|
||||
case OPERATION_END:
|
||||
this.type = type;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal event type: "+type);
|
||||
}
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new status event representing an update of the specified operation.
|
||||
*/
|
||||
public StatusEvent(Object source, int type, String operation, int minimum, int maximum, int value) {
|
||||
super(source);
|
||||
switch (type) {
|
||||
case OPERATION_START:
|
||||
case OPERATION_UPDATE:
|
||||
case OPERATION_END:
|
||||
this.type = type;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal event type: "+type);
|
||||
}
|
||||
this.operation = operation;
|
||||
this.minimum = minimum;
|
||||
this.maximum = maximum;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of event (OPERATION_START, OPERATION_UPDATE, or OPERATION_END).
|
||||
*/
|
||||
public int getType() { return type; }
|
||||
|
||||
/**
|
||||
* Returns a string describing the operation being performed.
|
||||
*/
|
||||
public String getOperation() { return operation; }
|
||||
|
||||
/**
|
||||
* Returns the start point of the operation.
|
||||
*/
|
||||
public int getMinimum() { return minimum; }
|
||||
|
||||
/**
|
||||
* Returns the end point of the operation.
|
||||
*/
|
||||
public int getMaximum() { return maximum; }
|
||||
|
||||
/**
|
||||
* Returns the current point in the operation.
|
||||
*/
|
||||
public int getValue() { return value; }
|
||||
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* StatusListener.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A callback interface for passing status messages.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public interface StatusListener extends EventListener {
|
||||
|
||||
/**
|
||||
* An operation started.
|
||||
*/
|
||||
public void statusOperationStarted(StatusEvent event);
|
||||
|
||||
/**
|
||||
* A progress update occurred.
|
||||
*/
|
||||
public void statusProgressUpdate(StatusEvent event);
|
||||
|
||||
/**
|
||||
* An operation completed.
|
||||
*/
|
||||
public void statusOperationEnded(StatusEvent event);
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* StatusSource.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
/**
|
||||
* An interface for defining that an object can pass status messages.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public interface StatusSource {
|
||||
|
||||
/**
|
||||
* Adds a status listener to this source.
|
||||
* @param l the listener
|
||||
*/
|
||||
public void addStatusListener(StatusListener l);
|
||||
|
||||
/**
|
||||
* Removes a status listener from this source.
|
||||
* @param l the listener
|
||||
*/
|
||||
public void removeStatusListener(StatusListener l);
|
||||
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Timer.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
/**
|
||||
* A timer class that wakes up listeners after a specified number of milliseconds.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public final class Timer extends Thread {
|
||||
|
||||
long time;
|
||||
long interval = 0;
|
||||
TimerListener listener;
|
||||
|
||||
/**
|
||||
* Constructs a timer.
|
||||
*/
|
||||
public Timer(TimerListener listener) {
|
||||
this(listener, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a timer with the specified interval, and starts it.
|
||||
*/
|
||||
public Timer(TimerListener listener, long interval) {
|
||||
this(listener, interval, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a timer with the specified interval, indicating whether or not to start it.
|
||||
*/
|
||||
public Timer(TimerListener listener, long interval, boolean start) {
|
||||
this.listener = listener;
|
||||
this.interval = interval;
|
||||
time = System.currentTimeMillis();
|
||||
setDaemon(true);
|
||||
setPriority(Thread.MIN_PRIORITY);
|
||||
if (start)
|
||||
start();
|
||||
}
|
||||
|
||||
// -- Accessor methods --
|
||||
|
||||
/**
|
||||
* Returns this timer's interval.
|
||||
*/
|
||||
public long getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this timer's interval.
|
||||
*/
|
||||
public void setInterval(long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs this timer.
|
||||
*/
|
||||
public void run() {
|
||||
boolean interrupt = false;
|
||||
while (!interrupt) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
wait(interval);
|
||||
} catch (InterruptedException e) {
|
||||
interrupt = true;
|
||||
}
|
||||
listener.timerFired(new TimerEvent(this, interval));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* TimerEvent.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* A timer event.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public class TimerEvent extends EventObject {
|
||||
|
||||
protected long ms;
|
||||
|
||||
// Creates a new timer event.
|
||||
TimerEvent(Timer timer, long ms) {
|
||||
super(timer);
|
||||
this.ms = ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timer that generated this event.
|
||||
*/
|
||||
public Timer getTimer() {
|
||||
return (Timer)source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of milliseconds since this timer last activated the listener.
|
||||
*/
|
||||
public long getMilliseconds() {
|
||||
return ms;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* TimerListener.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* Interface for classes that wnat to recieve timer events.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public interface TimerListener extends EventListener {
|
||||
|
||||
public void timerFired(TimerEvent event);
|
||||
|
||||
}
|
|
@ -1,671 +0,0 @@
|
|||
/*
|
||||
* Tree.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*
|
||||
* You may retrieve the latest version of this package at the knife home page,
|
||||
* located at http://www.dog.net.uk/knife/
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A utility class for manipulating objects in a tree structure.
|
||||
* <p>
|
||||
* This class provides a way to associate arbitrary objects with one another in a hierarchy.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public final class Tree {
|
||||
|
||||
int nparents = 0;
|
||||
Object[] parents;
|
||||
int[] nchildren;
|
||||
Object[][] children;
|
||||
int nelements = 0;
|
||||
Object[] elements;
|
||||
int[] depths;
|
||||
|
||||
int increment;
|
||||
Object LOCK = new Object();
|
||||
|
||||
/**
|
||||
* Constructs an empty tree.
|
||||
*/
|
||||
public Tree() {
|
||||
this(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty tree with the specified capacity increment.
|
||||
* @param increment the amount by which the capacity is increased when an array overflows.
|
||||
*/
|
||||
public Tree(int increment) {
|
||||
super();
|
||||
this.increment = (increment>0) ? increment : 1;
|
||||
clear();
|
||||
}
|
||||
|
||||
// Returns the elements index of the specified object, or -1 if no such element exists.
|
||||
private int elementIndex(Object object) {
|
||||
for (int i=0; i<nelements; i++)
|
||||
if (elements[i]==object)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the parents index of the specified object, or -1 if no such parent exists.
|
||||
private int parentIndex(Object object) {
|
||||
for (int i=0; i<nparents; i++)
|
||||
if (parents[i]==object)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent of the specified object,
|
||||
* or null if the object is a root or not a child in the tree.
|
||||
*/
|
||||
public Object getParent(Object child) {
|
||||
synchronized (LOCK) {
|
||||
return parentOf(child);
|
||||
}
|
||||
}
|
||||
|
||||
private Object parentOf(Object child) {
|
||||
for (int p = 0; p<nparents; p++) {
|
||||
for (int c = 0; c<nchildren[p]; c++)
|
||||
if (children[p][c]==child)
|
||||
return parents[p];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of children of the specified object,
|
||||
* or an empty array if the object is not a parent in the tree.
|
||||
*/
|
||||
public Object[] getChildren(Object parent) {
|
||||
synchronized (LOCK) {
|
||||
int p = parentIndex(parent);
|
||||
if (p>-1) {
|
||||
Object[] c = new Object[nchildren[p]];
|
||||
System.arraycopy(children[p], 0, c, 0, nchildren[p]);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of children of the specified object.
|
||||
*/
|
||||
public int getChildCount(Object parent) {
|
||||
synchronized (LOCK) {
|
||||
int p = parentIndex(parent);
|
||||
if (p>-1)
|
||||
return nchildren[p];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the specified object is contained in the tree.
|
||||
*/
|
||||
public boolean contains(Object object) {
|
||||
synchronized (LOCK) {
|
||||
return (elementIndex(object)>-1);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureRootCapacity(int amount) {
|
||||
// calculate the amount by which to increase arrays
|
||||
int block = ((int)(Math.max(Math.ceil((double)amount/(double)increment), 1)))*increment;
|
||||
// ensure capacity of elements
|
||||
if (elements.length<nelements+amount) {
|
||||
int len = elements.length;
|
||||
Object[] newelements = new Object[len+block];
|
||||
System.arraycopy(elements, 0, newelements, 0, nelements);
|
||||
elements = newelements;
|
||||
int[] newdepths = new int[len+block];
|
||||
System.arraycopy(depths, 0, newdepths, 0, nelements);
|
||||
depths = newdepths;
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureParentCapacity(int amount) {
|
||||
// calculate the amount by which to increase arrays
|
||||
int block = ((int)(Math.max(Math.ceil((double)amount/(double)increment), 1)))*increment;
|
||||
// ensure capacity of parents (and hence children in parent dimension)
|
||||
if (parents.length<nparents+1) {
|
||||
Object[] newparents = new Object[parents.length+increment];
|
||||
System.arraycopy(parents, 0, newparents, 0, nparents);
|
||||
parents = newparents;
|
||||
Object[][] newchildren = new Object[parents.length+increment][];
|
||||
System.arraycopy(children, 0, newchildren, 0, nparents);
|
||||
children = newchildren;
|
||||
int[] newnchildren = new int[parents.length+increment];
|
||||
System.arraycopy(nchildren, 0, newnchildren, 0, nparents);
|
||||
nchildren = newnchildren;
|
||||
}
|
||||
// ensure capacity of elements
|
||||
if (elements.length<nelements+amount) {
|
||||
int len = elements.length;
|
||||
Object[] newelements = new Object[len+block];
|
||||
System.arraycopy(elements, 0, newelements, 0, nelements);
|
||||
elements = newelements;
|
||||
int[] newdepths = new int[len+block];
|
||||
System.arraycopy(depths, 0, newdepths, 0, nelements);
|
||||
depths = newdepths;
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureChildCapacity(int amount, int parent) {
|
||||
// calculate the amount by which to increase arrays
|
||||
int block = ((int)(Math.max(Math.ceil((double)amount/(double)increment), 1)))*increment;
|
||||
// ensure capacity of children for this parent
|
||||
if (children[parent].length<nchildren[parent]+amount) {
|
||||
Object[] newchildren = new Object[children[parent].length+block];
|
||||
System.arraycopy(children[parent], 0, newchildren, 0, nchildren[parent]);
|
||||
children[parent] = newchildren;
|
||||
}
|
||||
// ensure capacity of elements
|
||||
if (elements.length<nelements+amount) {
|
||||
int len = elements.length;
|
||||
Object[] newelements = new Object[len+block];
|
||||
System.arraycopy(elements, 0, newelements, 0, nelements);
|
||||
elements = newelements;
|
||||
int[] newdepths = new int[len+block];
|
||||
System.arraycopy(depths, 0, newdepths, 0, nelements);
|
||||
depths = newdepths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a root to the tree.
|
||||
* Returns the root if it was added.
|
||||
*/
|
||||
public void add(Object object) {
|
||||
if (object==null)
|
||||
throw new NullPointerException("cannot add null to a tree");
|
||||
synchronized (LOCK) {
|
||||
int e;
|
||||
if ((e = elementIndex(object))>-1) // if we already have the object
|
||||
removeElement(e); // remove it
|
||||
ensureRootCapacity(1);
|
||||
elements[nelements] = object;
|
||||
depths[nelements] = 1;
|
||||
nelements++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds roots to the tree.
|
||||
*/
|
||||
public void add(Object[] objects) {
|
||||
synchronized (LOCK) {
|
||||
for (int i=0; i<objects.length; i++) {
|
||||
if (objects[i]==null)
|
||||
throw new NullPointerException("cannot add null to a tree");
|
||||
int e;
|
||||
if ((e = elementIndex(objects[i]))>-1) // if we already have the object
|
||||
removeElement(e); // remove it
|
||||
}
|
||||
ensureRootCapacity(objects.length);
|
||||
System.arraycopy(objects, 0, elements, nelements, objects.length);
|
||||
for (int i=nelements; i<nelements+objects.length; i++)
|
||||
depths[i] = 1;
|
||||
nelements += objects.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child to the specified parent in the tree.
|
||||
* @throws IllegalArgumentException if the parent does not exist in the tree or the child is the parent.
|
||||
*/
|
||||
public void add(Object parent, Object child) {
|
||||
if (parent==null)
|
||||
throw new NullPointerException("null parent specified");
|
||||
if (child==null)
|
||||
throw new NullPointerException("cannot add null to a tree");
|
||||
if (child==parent)
|
||||
throw new IllegalArgumentException("cannot add child to itself");
|
||||
synchronized (LOCK) {
|
||||
int p = parentIndex(parent), pe = -1;
|
||||
if (p<0) { // does it exist in the tree?
|
||||
if ((pe = elementIndex(parent))<0)
|
||||
throw new IllegalArgumentException("parent does not exist");
|
||||
} // so we'll add it to parents
|
||||
int e;
|
||||
if ((e = elementIndex(child))>-1) // if the child is already an element
|
||||
removeElement(e);
|
||||
|
||||
if (p<0) { // add the parent to parents
|
||||
p = nparents;
|
||||
ensureParentCapacity(1);
|
||||
parents[p] = parent;
|
||||
children[p] = new Object[increment];
|
||||
nchildren[p] = 0;
|
||||
nparents++;
|
||||
}
|
||||
ensureChildCapacity(1, p);
|
||||
children[p][nchildren[p]] = child;
|
||||
|
||||
// insert the child into elements and set its depth
|
||||
int depth = depth(parent);
|
||||
int off = pe+nchildren[p]+1;
|
||||
int len = nelements-off;
|
||||
Object[] buffer = new Object[len];
|
||||
System.arraycopy(elements, off, buffer, 0, len);
|
||||
elements[off] = child;
|
||||
System.arraycopy(buffer, 0, elements, off+1, len);
|
||||
int[] dbuffer = new int[len];
|
||||
System.arraycopy(depths, off, dbuffer, 0, len);
|
||||
depths[off] = depth+1;
|
||||
System.arraycopy(dbuffer, 0, depths, off+1, len);
|
||||
nelements++;
|
||||
|
||||
nchildren[p]++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds children to the specified parent in the tree.
|
||||
* @throws IllegalArgumentException if the parent does not exist in the tree or one of the children is the parent.
|
||||
*/
|
||||
public void add(Object parent, Object[] children) {
|
||||
if (parent==null)
|
||||
throw new NullPointerException("null parent specified");
|
||||
synchronized (LOCK) {
|
||||
int p = parentIndex(parent), pe = -1;
|
||||
if (p<0) { // does it exist in the tree?
|
||||
if ((pe = elementIndex(parent))<0)
|
||||
throw new IllegalArgumentException("parent does not exist");
|
||||
} // so we'll add it to parents
|
||||
for (int i=0; i<children.length; i++) {
|
||||
if (children[i]==null)
|
||||
throw new NullPointerException("cannot add null to a tree");
|
||||
if (children[i]==parent)
|
||||
throw new IllegalArgumentException("cannot add child to itself");
|
||||
int e;
|
||||
if ((e = elementIndex(children[i]))>-1) // if we already have the object
|
||||
removeElement(e); // remove it
|
||||
}
|
||||
if (p<0) { // add the parent to parents
|
||||
p = nparents;
|
||||
ensureParentCapacity(1);
|
||||
parents[p] = parent;
|
||||
this.children[p] = new Object[Math.max(increment, (children.length/increment)*increment)];
|
||||
nchildren[p] = 0;
|
||||
nparents++;
|
||||
}
|
||||
ensureChildCapacity(children.length, p);
|
||||
System.arraycopy(children, 0, this.children[p], nchildren[p], children.length);
|
||||
|
||||
// insert the children into elements and set their depths
|
||||
int depth = depth(parent);
|
||||
int off = pe+nchildren[p]+1;
|
||||
int len = nelements-off;
|
||||
Object[] buffer = new Object[len];
|
||||
System.arraycopy(elements, off, buffer, 0, len);
|
||||
System.arraycopy(children, 0, elements, off, children.length);
|
||||
System.arraycopy(buffer, 0, elements, off+children.length, len);
|
||||
|
||||
int[] dbuffer = new int[len];
|
||||
System.arraycopy(depths, off, dbuffer, 0, len);
|
||||
for (int i=off; i<off+children.length; i++)
|
||||
depths[i] = depth+1;
|
||||
System.arraycopy(dbuffer, 0, depths, off+children.length, len);
|
||||
nelements += children.length;
|
||||
|
||||
nchildren[p] += children.length;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the depth of an object in the tree
|
||||
private int depth(Object object) {
|
||||
Object parent = parentOf(object);
|
||||
if (parent==null)
|
||||
return 1;
|
||||
else
|
||||
return depth(parent)+1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified object and all its children from the tree.
|
||||
* Computationally pretty expensive.
|
||||
*/
|
||||
public void remove(Object object) {
|
||||
if (object==null)
|
||||
return; // i mean, really...
|
||||
synchronized (LOCK) {
|
||||
int e = elementIndex(object);
|
||||
if (e>-1)
|
||||
removeElement(e);
|
||||
}
|
||||
}
|
||||
|
||||
void removeElement(int e) {
|
||||
int len = 0;
|
||||
boolean removed = false;
|
||||
for (int p=0; p<nparents; p++) {
|
||||
if (parents[p]==elements[e]) {
|
||||
int nc = nchildren[p];
|
||||
try {
|
||||
//System.out.println("Removing "+elements[e]);
|
||||
//printArray("parents", parents, nparents);
|
||||
if ((len = nparents-p-1)>0) {
|
||||
System.arraycopy(parents, p+1, parents, p, len);
|
||||
System.arraycopy(children, p+1, children, p, len);
|
||||
System.arraycopy(nchildren, p+1, nchildren, p, len);
|
||||
}
|
||||
nparents--;
|
||||
//printArray("parents", parents, nparents);
|
||||
//printArray("elements", elements, nelements);
|
||||
if ((len = nelements-e-1)>0) {
|
||||
System.arraycopy(elements, e+1+nc, elements, e, len-nc);
|
||||
System.arraycopy(depths, e+1+nc, depths, e, len-nc);
|
||||
}
|
||||
nelements-=(nc+1);
|
||||
//printArray("elements", elements, nelements);
|
||||
removed = true;
|
||||
} catch (ArrayIndexOutOfBoundsException x) {
|
||||
System.out.println("arrayindexoutofboundsexception in tree:");
|
||||
System.out.println("p="+p+": "+parents[p]);
|
||||
System.out.println("e="+e+", nelements="+nelements+", elements.length="+elements.length+", nc="+nc+", len="+len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int p=0; p<nparents && !removed; p++) {
|
||||
for (int c = 0; c<nchildren[p] && !removed; c++) {
|
||||
if (children[p][c]==elements[e]) {
|
||||
if ((len = nchildren[p]-c-1)>0) {
|
||||
System.arraycopy(children[p], c+1, children[p], c, len);
|
||||
}
|
||||
nchildren[p]--;
|
||||
if ((len = nelements-e-1)>0) {
|
||||
System.arraycopy(elements, e+1, elements, e, len);
|
||||
System.arraycopy(depths, e+1, depths, e, len);
|
||||
}
|
||||
nelements--;
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!removed) {
|
||||
if ((len = nelements-e-1)>0) {
|
||||
System.arraycopy(elements, e+1, elements, e, len);
|
||||
System.arraycopy(depths, e+1, depths, e, len);
|
||||
}
|
||||
nelements--;
|
||||
}
|
||||
//printElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified objects and all their children from the tree.
|
||||
* @throws NullPointerException if an object does not exist in the tree.
|
||||
*/
|
||||
public void remove(Object[] objects) {
|
||||
for (int i=0; i<objects.length; i++)
|
||||
remove(objects[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removes the specified object's children from the tree.
|
||||
* @throws NullPointerException if the object does not exist in the tree.
|
||||
*/
|
||||
public void removeChildren(Object parent) {
|
||||
synchronized (LOCK) {
|
||||
removeChildrenImpl(parent);
|
||||
}
|
||||
}
|
||||
|
||||
void removeChildrenImpl(Object parent) {
|
||||
int p = parentIndex(parent);
|
||||
if (p>-1) {
|
||||
for (int c=0; c<nchildren[p]; c++)
|
||||
removeChildrenImpl(children[p][c]);
|
||||
children[p] = new Object[increment];
|
||||
nchildren[p] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all objects from the tree.
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (LOCK) {
|
||||
parents = new Object[increment];
|
||||
nparents = 0;
|
||||
nchildren = new int[increment];
|
||||
for (int i=0; i<increment; i++)
|
||||
nchildren[i] = 0;
|
||||
children = new Object[increment][increment];
|
||||
elements = new Object[increment];
|
||||
depths = new int[increment];
|
||||
nelements = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the depth of the specified object in the tree.
|
||||
* Roots have a depth of 1.
|
||||
*/
|
||||
public int getDepth(Object object) {
|
||||
synchronized (LOCK) {
|
||||
int e = elementIndex(object);
|
||||
if (e==-1) {
|
||||
//System.out.println("Warning: "+object+" not found");
|
||||
//new Throwable().printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
return depths[e];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the roots in this tree.
|
||||
*/
|
||||
public Object[] getRoots() {
|
||||
synchronized (LOCK) {
|
||||
Vector v = new Vector();
|
||||
for (int i=0; i<nelements; i++) {
|
||||
if (depths[i]==1)
|
||||
v.addElement(elements[i]);
|
||||
}
|
||||
Object[] roots = new Object[v.size()];
|
||||
v.copyInto(roots);
|
||||
return roots;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of roots in this tree.
|
||||
*/
|
||||
public int getRootCount() {
|
||||
synchronized (LOCK) {
|
||||
Vector v = new Vector();
|
||||
for (int i=0; i<nelements; i++) {
|
||||
if (depths[i]==1)
|
||||
v.addElement(elements[i]);
|
||||
}
|
||||
return v.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the objects in this tree in depth-first order.
|
||||
*/
|
||||
public Object[] getTree() {
|
||||
synchronized (LOCK) {
|
||||
Object[] objects = new Object[nelements];
|
||||
System.arraycopy(elements, 0, objects, 0, nelements);
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of objects in this tree.
|
||||
*/
|
||||
public int getTreeCount() {
|
||||
return nelements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether there are any children in this tree.
|
||||
*/
|
||||
public boolean hasChildren() {
|
||||
synchronized (LOCK) {
|
||||
for (int p=0; p<nparents; p++)
|
||||
if (nchildren[p]>0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the objects in the tree according to the specified object collator.
|
||||
* This has no effect if a collator has not been defined.
|
||||
*/
|
||||
public void sort(ObjectCollator collator) {
|
||||
if (collator==null) throw new NullPointerException("null collator");
|
||||
synchronized (LOCK) {
|
||||
Sorter sorter = this.new Sorter(collator);
|
||||
elements = sorter.newelements;
|
||||
depths = sorter.newdepths;
|
||||
}
|
||||
}
|
||||
|
||||
class Sorter {
|
||||
|
||||
Object[] newelements;
|
||||
int[] newdepths;
|
||||
int count = 0;
|
||||
|
||||
Sorter(ObjectCollator collator) {
|
||||
// first sort the roots
|
||||
Vector v = new Vector();
|
||||
for (int i=0; i<nelements; i++) {
|
||||
if (depths[i]==1)
|
||||
v.addElement(elements[i]);
|
||||
}
|
||||
Object[] roots = new Object[v.size()];
|
||||
v.copyInto(roots);
|
||||
sort(roots, 0, roots.length-1, collator);
|
||||
// now sort the children of each parent
|
||||
for (int p=0; p<nparents; p++)
|
||||
sort(children[p], 0, nchildren[p]-1, collator);
|
||||
// now create a new elements array positioning the elements according to the new order
|
||||
newelements = new Object[elements.length];
|
||||
newdepths = new int[elements.length];
|
||||
for (int r=0; r<roots.length; r++) {
|
||||
newelements[count] = roots[r];
|
||||
newdepths[count] = depths[elementIndex(roots[r])];
|
||||
count++;
|
||||
appendChildren(roots[r]);
|
||||
}
|
||||
}
|
||||
|
||||
void appendChildren(Object parent) {
|
||||
for (int p=0; p<nparents; p++) {
|
||||
if (parent==parents[p]) {
|
||||
for (int c=0; c<nchildren[p]; c++) {
|
||||
newelements[count] = children[p][c];
|
||||
newdepths[count] = getDepth(children[p][c]);
|
||||
count++;
|
||||
appendChildren(children[p][c]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Quicksort algorithm.
|
||||
static void sort(Object[] objects, int first, int last, ObjectCollator collator) {
|
||||
int lo = first, hi = last;
|
||||
Object mid;
|
||||
if (last>first) {
|
||||
mid = objects[(first+last)/2];
|
||||
while (lo<=hi) {
|
||||
while (lo<last && collator.compare(objects[lo], mid)<0)
|
||||
lo += 1;
|
||||
while (hi>first && collator.compare(objects[hi], mid)>0)
|
||||
hi -= 1;
|
||||
if (lo<=hi) { // swap
|
||||
Object tmp = objects[lo];
|
||||
objects[lo] = objects[hi];
|
||||
objects[hi] = tmp;
|
||||
lo += 1;
|
||||
hi -= 1;
|
||||
}
|
||||
}
|
||||
if (first<hi)
|
||||
sort(objects, first, hi, collator);
|
||||
if (lo<last)
|
||||
sort(objects, lo, last, collator);
|
||||
}
|
||||
}
|
||||
|
||||
public void printArray(String name, Object[] array, int count) {
|
||||
System.out.println(name+": length="+array.length+", count="+count);
|
||||
for (int i=0; i<count; i++)
|
||||
System.out.println("\t"+array[i]);
|
||||
}
|
||||
|
||||
public void printElements() {
|
||||
System.out.println("elements=");
|
||||
for (int i=0; i<nelements; i++) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(Integer.toString(depths[i]));
|
||||
for (int j=0; j<depths[i]; j++)
|
||||
buffer.append(" ");
|
||||
buffer.append(elements[i]);
|
||||
System.out.println(buffer.toString());
|
||||
}
|
||||
System.out.println("tree=");
|
||||
for (int p=0; p<nparents; p++) {
|
||||
System.out.println(parents[p]);
|
||||
for (int c=0; c<nchildren[p]; c++)
|
||||
System.out.println(" "+children[p][c]);
|
||||
}
|
||||
}
|
||||
|
||||
// -- Utility methods --
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(getClass().getName());
|
||||
buffer.append("[");
|
||||
buffer.append("nelements="+nelements);
|
||||
buffer.append(",elements.length="+elements.length);
|
||||
buffer.append(",depths.length="+depths.length);
|
||||
buffer.append(",nparents="+nparents);
|
||||
buffer.append(",parents.length="+parents.length);
|
||||
buffer.append("]");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
/*
|
||||
* TreeCollator.java
|
||||
* Copyright (C) 1998 dog <dog@dog.net.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A class for comparing objects in a tree.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 2.0alpha
|
||||
*/
|
||||
public class TreeCollator extends Collator {
|
||||
|
||||
protected Collator collator;
|
||||
|
||||
protected boolean descending = false;
|
||||
|
||||
/**
|
||||
* Constructs a TreeCollator for the default locale.
|
||||
*/
|
||||
public TreeCollator() {
|
||||
collator = Collator.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a TreeCollator for the specified locale.
|
||||
*/
|
||||
public TreeCollator(Locale locale) {
|
||||
collator = Collator.getInstance(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this collator returns the opposite of any comparison.
|
||||
* @see #setDescending
|
||||
*/
|
||||
public boolean isDescending() { return descending; }
|
||||
|
||||
/**
|
||||
* Sets whether this collator returns the opposite of any comparison.
|
||||
* @param descending true if this collator returns the opposite of any comparison, false otherwise
|
||||
* @see #setDescending
|
||||
*/
|
||||
public void setDescending(boolean descending) { this.descending = descending; }
|
||||
|
||||
/**
|
||||
* Utility method to return the opposite of a comparison if descending is true.
|
||||
*/
|
||||
protected int applyDescending(int comparison) {
|
||||
return (!descending ? comparison : -comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the source string to the target string according to the collation rules for this Collator.
|
||||
* Returns an integer less than, equal to or greater than zero depending on whether the source String
|
||||
* is less than, equal to or greater than the target string.
|
||||
* @param source the source string.
|
||||
* @param target the target string.
|
||||
* @see java.text.CollationKey
|
||||
*/
|
||||
public int compare(String source, String target) {
|
||||
return applyDescending(collator.compare(source, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the source object to the target object according to the collation rules for this Collator.
|
||||
* Returns an integer less than, equal to or greater than zero depending on whether the source object
|
||||
* is less than, equal to or greater than the target object.
|
||||
* Objects that can validly be compared by such means include:<ul>
|
||||
* <li>Boolean - false is less than true, can only be compared with another Boolean
|
||||
* <li>Byte
|
||||
* <li>Date - before is less than after, can only be compared with another Date
|
||||
* <li>Double
|
||||
* <li>Float
|
||||
* <li>Long
|
||||
* <li>Integer
|
||||
* <li>Short
|
||||
* <li>String
|
||||
* @param source the source object.
|
||||
* @param target the target object.
|
||||
*/
|
||||
public int compare(Object source, Object target) {
|
||||
if (source instanceof String) {
|
||||
if (target instanceof String)
|
||||
return applyDescending(collator.compare((String)source, (String)target));
|
||||
else if (target instanceof Number)
|
||||
return applyDescending(collator.compare((String)source, target.toString()));
|
||||
} else if (source instanceof Integer) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending(((Number)target).intValue()-((Integer)source).intValue());
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Double) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).doubleValue()-((Double)source).doubleValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Long) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).longValue()-((Long)source).longValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Float) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).floatValue()-((Float)source).floatValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Byte) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).byteValue()-((Byte)source).byteValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Short) {
|
||||
if (target instanceof Number)
|
||||
return applyDescending((int)(((Number)target).shortValue()-((Short)source).shortValue()));
|
||||
else if (target instanceof String)
|
||||
return applyDescending(collator.compare(source.toString(), (String)target));
|
||||
} else if (source instanceof Boolean) {
|
||||
if (target instanceof Boolean) {
|
||||
boolean s = ((Boolean)source).booleanValue(), t = ((Boolean)target).booleanValue();
|
||||
if (!s && t) return applyDescending(-1); else if (s && !t) return applyDescending(1);
|
||||
}
|
||||
} else if (source instanceof Date) {
|
||||
if (target instanceof Date) {
|
||||
Date s = (Date)source, t = (Date)target;
|
||||
if (s.before(t)) return applyDescending(-1); else if (s.after(t)) return applyDescending(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the String into a series of bits that can be compared bitwise to other CollationKeys.
|
||||
* CollationKeys provide better performance than Collator.compare when Strings are involved in multiple comparisons.
|
||||
* @param source the string to be transformed into a collation key.
|
||||
* @return the CollationKey for the given String based on this Collator's collation rules. If the source String is null, a null CollationKey is returned.
|
||||
* @see java.text.CollationKey
|
||||
* @see #compare
|
||||
*/
|
||||
public CollationKey getCollationKey(String source) {
|
||||
return collator.getCollationKey(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for comparing the equality of two strings based on this Collator's collation rules.
|
||||
* @param source the source string to be compared with.
|
||||
* @param target the target string to be compared with.
|
||||
* @return true if the strings are equal according to the collation rules, false otherwise.
|
||||
* @see #compare
|
||||
*/
|
||||
public boolean equals(String source, String target) {
|
||||
return collator.equals(source, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this Collator's strength property.
|
||||
* The strength property determines the minimum level of difference considered significant during comparison.
|
||||
* See the Collator class description for an example of use.
|
||||
* @return this Collator's current strength property.
|
||||
* @see #setStrength
|
||||
*/
|
||||
public int getStrength() { return collator.getStrength(); }
|
||||
|
||||
/**
|
||||
* Sets this Collator's strength property.
|
||||
* The strength property determines the minimum level of difference considered significant during comparison.
|
||||
* See the Collator class description for an example of use.
|
||||
* @param newStrength the new strength value.
|
||||
* @exception IllegalArgumentException if the new strength value is not one of PRIMARY, SECONDARY, TERTIARY or IDENTICAL.
|
||||
* @see #getStrength
|
||||
*/
|
||||
public void setStrength(int newStrength) { collator.setStrength(newStrength); }
|
||||
|
||||
/**
|
||||
* Get the decomposition mode of this Collator.
|
||||
* Decomposition mode determines how Unicode composed characters are handled.
|
||||
* Adjusting decomposition mode allows the user to select between faster and more complete collation behavior.
|
||||
* The three values for decomposition mode are: <ul>
|
||||
* <li>NO_DECOMPOSITION,
|
||||
* <li>CANONICAL_DECOMPOSITION
|
||||
* <li>FULL_DECOMPOSITION.
|
||||
* </ul>See the documentation for these three constants for a description of their meaning.
|
||||
* @return the decomposition mode
|
||||
* @see #setDecomposition
|
||||
*/
|
||||
public int getDecomposition() { return collator.getDecomposition(); }
|
||||
|
||||
/**
|
||||
* Set the decomposition mode of this Collator.
|
||||
* See getDecomposition for a description of decomposition mode.
|
||||
* @param decompositionMode the new decomposition mode
|
||||
* @throws IllegalArgumentException if the given value is not a valid decomposition mode.
|
||||
* @see #getDecomposition
|
||||
*/
|
||||
public void setDecomposition(int decompositionMode) { collator.setDecomposition(decompositionMode); }
|
||||
|
||||
public int hashCode() { return collator.hashCode(); }
|
||||
|
||||
public boolean equals(Object other) { return (other instanceof TreeCollator) ? collator.equals(((TreeCollator)other).collator) : false; }
|
||||
|
||||
/**
|
||||
* Provides a string description of this object.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(getClass().getName());
|
||||
buffer.append("[");
|
||||
buffer.append(paramString().toString());
|
||||
buffer.append("]");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
protected StringBuffer paramString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("strength=");
|
||||
switch (getStrength()) {
|
||||
case PRIMARY:
|
||||
buffer.append("PRIMARY");
|
||||
break;
|
||||
case SECONDARY:
|
||||
buffer.append("SECONDARY");
|
||||
break;
|
||||
case TERTIARY:
|
||||
buffer.append("TERTIARY");
|
||||
break;
|
||||
case IDENTICAL:
|
||||
buffer.append("IDENTICAL");
|
||||
break;
|
||||
default:
|
||||
buffer.append("unknown");
|
||||
}
|
||||
buffer.append(",decomposition=");
|
||||
switch (getDecomposition()) {
|
||||
case NO_DECOMPOSITION:
|
||||
buffer.append("NO_DECOMPOSITION");
|
||||
break;
|
||||
case CANONICAL_DECOMPOSITION:
|
||||
buffer.append("CANONICAL_DECOMPOSITION");
|
||||
break;
|
||||
case FULL_DECOMPOSITION:
|
||||
buffer.append("FULL_DECOMPOSITION");
|
||||
break;
|
||||
default:
|
||||
buffer.append("unknown");
|
||||
}
|
||||
if (descending) buffer.append(",descending");
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* TreeEvent.java
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Knife.
|
||||
*
|
||||
* The Initial Developer of the Original Code is dog.
|
||||
* Portions created by dog are Copyright (C) 1998 dog <dog@dog.net.uk>. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): n/a.
|
||||
*/
|
||||
|
||||
package dog.util;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* A tree event.
|
||||
*
|
||||
* @author dog@dog.net.uk
|
||||
* @version 1.0final
|
||||
*/
|
||||
public class TreeEvent extends ItemEvent {
|
||||
|
||||
/**
|
||||
* The item collapsed state change type.
|
||||
*/
|
||||
public static final int COLLAPSED = 3;
|
||||
|
||||
/**
|
||||
* The item expanded state change type.
|
||||
*/
|
||||
public static final int EXPANDED = 4;
|
||||
|
||||
/**
|
||||
* Constructs a TreeEvent object with the specified ItemSelectable source,
|
||||
* type, item, and item select state.
|
||||
* @param source the ItemSelectable object where the event originated
|
||||
* @id the event type
|
||||
* @item the item where the event occurred
|
||||
* @stateChange the state change type which caused the event
|
||||
*/
|
||||
public TreeEvent(ItemSelectable source, int id, Object item, int stateChange) {
|
||||
super(source, id, item, stateChange);
|
||||
}
|
||||
|
||||
public String paramString() {
|
||||
Object item = getItem();
|
||||
int stateChange = getStateChange();
|
||||
|
||||
String typeStr;
|
||||
switch (id) {
|
||||
case ITEM_STATE_CHANGED:
|
||||
typeStr = "ITEM_STATE_CHANGED";
|
||||
break;
|
||||
default:
|
||||
typeStr = "unknown type";
|
||||
}
|
||||
|
||||
String stateStr;
|
||||
switch (stateChange) {
|
||||
case SELECTED:
|
||||
stateStr = "SELECTED";
|
||||
break;
|
||||
case DESELECTED:
|
||||
stateStr = "DESELECTED";
|
||||
break;
|
||||
case COLLAPSED:
|
||||
stateStr = "COLLAPSED";
|
||||
break;
|
||||
case EXPANDED:
|
||||
stateStr = "EXPANDED";
|
||||
break;
|
||||
default:
|
||||
stateStr = "unknown type";
|
||||
}
|
||||
return typeStr + ",item="+item + ",stateChange="+stateStr;
|
||||
}
|
||||
|
||||
}
|
Загрузка…
Ссылка в новой задаче