1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
|
/*
* java-gnome, a UI library for writing GTK and GNOME programs from Java!
*
* Copyright © 2008-2010 Operational Dynamics Consulting, Pty Ltd and Others
*
* The code in this file, and the program it is a part of, is made available
* to you by its authors as open source software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License version
* 2 ("GPL") as published by the Free Software Foundation.
*
* 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 GPL for more details.
*
* You should have received a copy of the GPL along with this program. If not,
* see http://www.gnu.org/licenses/. The authors of this program may be
* contacted through http://java-gnome.sourceforge.net/.
*/
package textview;
/*
* The smiley image used in this program is from the Tango Icon Theme, whose
* authors make available under the Creative Commons Attribution Share-Alike
* licence version 2.5. See http://tango-project.org/ for more details.
*/
import java.io.FileNotFoundException;
import org.gnome.gdk.Event;
import org.gnome.gdk.EventKey;
import org.gnome.gdk.Keyval;
import org.gnome.gdk.Pixbuf;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.IconSize;
import org.gnome.gtk.ScrolledWindow;
import org.gnome.gtk.Stock;
import org.gnome.gtk.TextBuffer;
import org.gnome.gtk.TextIter;
import org.gnome.gtk.TextTag;
import org.gnome.gtk.TextView;
import org.gnome.gtk.VBox;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;
import org.gnome.pango.Style;
import org.gnome.pango.Weight;
import static org.freedesktop.bindings.Time.formatTime;
import static org.gnome.gtk.PolicyType.ALWAYS;
import static org.gnome.gtk.PolicyType.NEVER;
import static org.gnome.gtk.ShadowType.IN;
import static org.gnome.gtk.WrapMode.NONE;
import static org.gnome.gtk.WrapMode.WORD;
/**
* An example of rendering multi-line text in an application.
*
* There comes a point when it is difficult to demonstrate complex
* functionality in a trivial example, so so illustrate usage of the powerful
* TextView/TextBuffer APIs, we so we have opted to do something a bit more
* involved.
*
* This program creates the conversation window you might see in a typical
* graphical instant messenger. It has a TextView displaying the conversation
* above, and uses various formatting to differentiate between incoming
* messages and outgoing ones. There is a second TextView at the bottom where
* the user can write the messages and "send" them. Finally, a tiny worker
* thread is kicked off to simulate incoming conversation.
*
* Enjoy!
*
* @author Andrew Cowie
* @author Stefan Prelle
* @author Serkan Kaba
*/
public class ExampleInstantMessenger
{
private final TextBuffer buffer;
private final TextView incoming;
private final TextView outgoing;
private final Pixbuf smiley;
private final TextTag grey, italics, blue;
private ExampleInstantMessenger() {
final Window window;
final VBox top;
final ScrolledWindow scroll1, scroll2;
final Thread other;
Pixbuf tmp;
/*
* Start with the usual establishment of a Window to contain the
* example.
*/
window = new Window();
window.setTitle("Instant Messaging");
window.setDefaultSize(300, 200);
top = new VBox(false, 3);
window.add(top);
window.connect(new Window.DeleteEvent() {
public boolean onDeleteEvent(Widget source, Event event) {
Gtk.mainQuit();
return false;
}
});
/*
* Create a TextView which will display incoming text messages (and
* also echo messages as they are sent). It is set up to be read only
* and to not have a cursor, thereby conveying the impression that it
* is just a display (a cursor especially would suggest that the text
* there can be changed).
*/
buffer = new TextBuffer();
incoming = new TextView(buffer);
incoming.setEditable(false);
incoming.setCursorVisible(false);
incoming.setPaddingBelowParagraph(10);
/*
* We want word wrapping, otherwise messages wider that the screen
* width will be truncated. We also need to set up vertical scrolling
* so that as the conversation continues it won't be inaccessible off
* the bottom of the screen.
*/
incoming.setWrapMode(WORD);
scroll1 = new ScrolledWindow();
scroll1.setPolicy(NEVER, ALWAYS);
scroll1.setShadowType(IN);
scroll1.add(incoming);
top.packStart(scroll1, true, true, 0);
/*
* Create the place for the user to enter messages they want to send.
*
* The interesting part here is that when the user presses Enter in
* the TextView it "sends" a message and appends it to the log in the
* incoming TextView.
*/
outgoing = new TextView();
outgoing.setSizeRequest(0, 20);
outgoing.setAcceptsTab(false);
outgoing.setWrapMode(NONE);
scroll2 = new ScrolledWindow();
scroll2.setPolicy(NEVER, NEVER);
scroll2.setShadowType(IN);
scroll2.add(outgoing);
top.packStart(scroll2, false, false, 0);
outgoing.connect(new Widget.KeyPressEvent() {
public boolean onKeyPressEvent(Widget source, EventKey event) {
if (event.getKeyval() == Keyval.Return) {
final TextBuffer buffer;
final String str;
buffer = outgoing.getBuffer();
str = buffer.getText();
/*
* Append the text in the TextView to the TextBuffer
* backing the incoming display.
*/
appendMessage(str, true);
/*
* But now clear the TextView so that we can enter another
* message.
*/
buffer.setText("");
/*
* And don't process the keystroke further.
*/
return true;
}
return false;
}
});
/*
* Add English spellchecking to input TextView.
*/
outgoing.attachSpell("en");
/*
* TextTags are how you apply formatting to content. We'll create a
* few for later use in the display.
*/
grey = new TextTag();
grey.setForeground("#777777");
italics = new TextTag();
italics.setStyle(Style.ITALIC);
italics.setForeground("darkgreen");
blue = new TextTag();
blue.setWeight(Weight.BOLD);
blue.setForeground("blue");
/*
* Almost there. Quickly load an image that we'll use later to replace
* text smileys with. Since people frequently screw up relative paths
* when running things, we'll go to some trouble to load the broken
* image icon instead if we can't find our smiley.
*/
try {
tmp = new Pixbuf("doc/examples/textview/face-smile.png");
} catch (FileNotFoundException fnfe) {
System.err.println("Warning: smiley image " + fnfe.getMessage());
tmp = Gtk.renderIcon(window, Stock.MISSING_IMAGE, IconSize.BUTTON);
}
smiley = tmp;
/*
* Put the Window and all its children on screen.
*/
window.showAll();
/*
* Make sure the user's text Entry has the keyboard focus. For a
* number of reasons, this won't work until late in the game after
* everything else is packed. If you try it earlier something else
* will end up with focus despite this call having been made.
*/
outgoing.grabFocus();
/*
* And start the "conversation" :)
*/
other = new IncomingConversation();
other.start();
}
/**
* Append a received (or sent) message to the incoming display.
*/
/*
* For fun, we translate the smile emoticon into an image, giving us an
* opportunity to demonstrate adding non-text elements to a TextBuffer.
*/
private void appendMessage(String msg, boolean outbound) {
final TextIter end;
final long now;
final String timestamp;
final TextTag colour;
int i;
int prev;
/*
* Get a TextIter pointing at the end of the existing text.
*/
end = buffer.getIterEnd();
/*
* Start with a paragraph separator and a timestamp. We colour the
* timestamp a lighter colour so as to not distract from the text.
*/
buffer.insert(end, "\n");
now = System.currentTimeMillis() / 1000;
timestamp = formatTime("%H:%M:%S\t", now);
buffer.insert(end, timestamp, grey);
/*
* Loop over what we're going to add, replacing text smileys with
* graphical ones. As for the text we write, if the user sent it we'll
* make it blue but if incoming we'll leave it black.
*/
if (outbound) {
colour = blue;
} else {
colour = null;
}
prev = 0;
while ((i = msg.indexOf(":)", prev)) != -1) {
buffer.insert(end, msg.substring(prev, i), colour);
buffer.insert(end, smiley);
i += 2;
prev = i;
}
buffer.insert(end, msg.substring(prev), colour);
/*
* We would be done, except that we need to scroll the TextView to
* show the message just appended. Otherwise the display will stay
* scrolled to top despite the fact that more message traffic is
* coming in. An instant messenger shows the recently arrived traffic
* on screen, letting older messages go off the top.
*/
incoming.scrollTo(end);
}
/**
* When a conversation starts we want to indicate who it is with.
*/
private void startConversationWith(String who) {
final TextIter pointer;
/*
* Place a message at the top of the display indicating who is writing
* in.
*/
pointer = buffer.getIterStart();
buffer.insert(pointer, "Starting conversation with " + who, italics);
}
/*
* We end with the program's main() method where we initialize GTK, call
* the constructor to build the GUI and then start the main event loop.
*/
public static void main(String[] args) {
Gtk.init(args);
new ExampleInstantMessenger();
Gtk.main();
}
/*
* And that's it! The remainder of this file is just some contrived
* infrastructure to simulate a conversation. Run this example and you'll
* see it all in action!
*/
class IncomingConversation extends Thread
{
private final String[] messages;
private IncomingConversation() {
/*
* Mark this thread as a daemon thread, else the main thread
* terminating after Gtk.main() returns will not end the program.
*/
this.setDaemon(true);
/*
* Some silly messages to use to fake incoming conversation.
*/
messages = new String[] {
"Hello there!",
"Will you be my friend? :)",
"I live in Kenya. " + "It's nice here because it is so warm.",
"Someday, though, I want to see snow. " + "Perhaps I will go climb Kilimanjaro.",
"Did you see the marathon on the last day of the Olympics? "
+ "What a run by Samuel Wanjiru! " + "We are all so proud."
};
startConversationWith("Catherine Ojiambo");
}
public void run() {
for (int i = 0; i < messages.length; i++) {
try {
sleep((int) (1000 + i * 2000 * Math.random()));
} catch (InterruptedException ie) {
}
appendMessage(messages[i], false);
}
}
}
}
|