📄 threadedemails.java
字号:
/* *
* Constant represents that message at this "position" is root message.
*
* @see Enumerator#actualRootChild
*/
// private static final int ROOT_MESSAGE = -1;
/**
* Class enables iterating over the structure.
* There are two indexes:<ul>
* <li>root index - index to the root messages vector</li>
* <li>child index - index to the vector of children for root message</li>
* </ul>
* When child index is {@link ThreadedEmails#ROOT_MESSAGE}, that means that
* the message to retrieve is the one from root message vector.
* When root index is size of root messages vector, taht means that we are
* at the end of all messages (there are no more elements).
*
* @author Betlista
*/
//#ifdef MUJMAIL_TEST_BACKWARD_ITERATING
//# public
//#else
private
//#endif
class Enumerator implements Enumeration {
/**
* <p>
* Index of next message, used for simple implementation
* of {@link #hasMoreElements()} method.
* </p>
* <p>
* When index value is for example 3 that means that next message will
* be returned the 4th message in structure (index starts with 0).
* </p>
*/
private int index;
/**
* Reference to actual message.
*/
private MessageHeader actual;
/**
* Idea of this enumeration is that it points to next element, this is
* the invariant.
*/
public Enumerator() {
index = 0;
actual = null;
}
/**
* Returns <code>true</code> if there are more elements.
*
* @return <code>true</code> if there are more elements in enumeration,
* <code>false</code> otherwise
*/
public boolean hasMoreElements() {
return index < size;
}
/**
* Method is just synonym for {@link #hasMoreElements()} method.
*/
//#ifdef MUJMAIL_TEST_BACKWARD_ITERATING
//# public
//#else
private
//#endif
boolean hasNextElement() {
return hasMoreElements();
}
/**
* Returns next element in enumeration.
*
* @return MessageHeader next message
* @throws NoSuchElementException if there are no more elements.
* @see #hasMoreElements()
*/
public Object nextElement() throws NoSuchElementException {
if ( !hasNextElement() ) {
throw new NoSuchElementException();
}
MessageHeader messageHeader = null;
if ( actual == null ) {
messageHeader = (MessageHeader)rootMessages.elementAt( 0 );
} else {
boolean actualChanged = false;
while ( messageHeader == null ) {
if ( !actualChanged ) {
messageHeader = getFirstChild();
}
if ( messageHeader == null ) {
messageHeader = getSibling(true);
}
if ( messageHeader == null ) {
// actual cannot be null here
// setting of
actual = (MessageHeader)parents.get( actual.getThreadingMessageID() );
actualChanged = true;
messageHeader = getSibling(true);
}
}
}
actual = messageHeader;
++index;
return messageHeader;
}
//#ifdef MUJMAIL_TEST_BACKWARD_ITERATING
//# public
//#else
private
//#endif
boolean hasPreviousElement() {
/* If index is 0 that means that next returned message will be
* the 1st message, so there was no message returned yet and
* that why it has no previous message.
*
* If index is 1 the actual message is the 1st one and it has
* no previous message too.
*/
return index > 1;
}
/**
* Returns the previous message for actual one.
*
* @return previous message for actual ones
*/
//#ifdef MUJMAIL_TEST_BACKWARD_ITERATING
//# public
//#else
private
//#endif
Object previousElement() {
if ( !hasPreviousElement() ) {
throw new NoSuchElementException();
}
MessageHeader messageHeader = null;
/* First of all we need to retrieve the last child message
* of the previous sibling tree.
* Example:
* --root
* |--1
* | |--2
* | \--3
* | |--4
* | \--5 <- previous
* \--6 <- actual
* If actual message is 6, than previous message is 5
* => previous sibling of 6 is 1 and last child is 5
*/
MessageHeader parent = (MessageHeader)parents.get( actual.getThreadingMessageID() );
if ( parent == null ) {
MessageHeader sibling = getSibling( false );
MessageHeader lastChild = getLastChild( sibling.getThreadingMessageID() );
if ( lastChild == null ) {
messageHeader = sibling;
} else {
messageHeader = lastChild;
}
} else {
Vector childVector = (Vector)children.get( parent.getThreadingMessageID() );
if ( childVector != null ) {
final int index = childVector.indexOf( actual );
if ( index > 0 ) {
MessageHeader previousSibling = (MessageHeader)childVector.elementAt( index - 1 );
MessageHeader lastChild = getLastChild( previousSibling.getThreadingMessageID() );
if ( lastChild == null ) {
messageHeader = previousSibling;
} else {
messageHeader = lastChild;
}
} else {
messageHeader = parent;
}
}
}
actual = messageHeader;
--index;
return messageHeader;
}
/**
* Method returns last child of the subtree with message identified
* by rootThreadingID as root of this subtree.
*
* @param rootThreadingID identification of the message that represents
* subtree root
* @return last child of subtree or null if root message have no child.
*/
private MessageHeader getLastChild( final String rootThreadingID ) {
MessageHeader lastChild = null;
Vector childVector = (Vector)children.get( rootThreadingID );
if ( childVector != null ) {
lastChild = (MessageHeader)childVector.elementAt( childVector.size() - 1 );
MessageHeader newLastChild = getLastChild( lastChild.getThreadingMessageID() );
if ( newLastChild != null ) {
lastChild = newLastChild;
}
}
return lastChild;
}
/**
* Returns first child for actual message.<br>
* Example:
* <pre>
* -- Msg1
* |-- Msg3
* \-- Msg4
* -- Msg2
* </pre>
* For Msg1 returns Msg3, for other message in this example returns null.
*
* @return first child for actual message or null
*/
private MessageHeader getFirstChild() {
Object o = children.get( actual.getThreadingMessageID() );
if ( o == null ) {
return null;
}
Vector childVector = (Vector)o;
return (MessageHeader)childVector.elementAt( 0 );
}
/**
* Returns sibling for actual message.
* Example:
* <pre>
* -- Msg1
* |-- Msg3
* \-- Msg4
* -- Msg2
* </pre>
* For Msg1 returns Msg2, for Msg3 returns Msg4, for all other messages
* returns null (have no sibling).
*
* @param next specifies if we want next (<code>true</code>) sibling
* or the previous one (<code>false</code>)
* @return sibling for actual message or null
*/
private MessageHeader getSibling( final boolean next ) {
final int shift = next?1:-1;
final MessageHeader messageHeader;
// get parent
final String actualMessageID = actual.getThreadingMessageID();
final int index;
MessageHeader parentMessage = (MessageHeader)parents.get( actualMessageID );
if ( parentMessage == null ) {
// have no parent, get next root message or first child (if some exist)
index = rootMessages.indexOf( actual );
// how we know that there is such message?
// it's simple: this method is called only from nextElement()
// or previousElement() methods, so there was check if such
// element exist
messageHeader = (MessageHeader)rootMessages.elementAt( index + shift );
} else {
// in this case we are not operating with root messages,
// so there is no guarantee that sibling exists
// child vector cannot be null here, because actual message
// is one of the children
Vector childVector = (Vector)children.get( parentMessage.getThreadingMessageID() );
index = childVector.indexOf( actual );
if ( next && index == childVector.size() - 1 ) {
// when we want next message, but actual is last one
// in child vector so there is no sibling
messageHeader = null;
} else if ( !next && index == 0 ) {
// when we want previous message, but actual is first one
// in child vector so there is no sibling
messageHeader = null;
} else {
messageHeader = (MessageHeader)childVector.elementAt( index + shift );
}
}
return messageHeader;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -