From 6764738d92df13f63c1dd67f54ddea5deebc8bcc Mon Sep 17 00:00:00 2001 From: whatever Date: Mon, 14 Sep 2026 20:19:29 -0400 Subject: [PATCH] created mirror --- C++/README | 5 + CODING | 122 + ChangeLog | 4403 +++++++++++++++++ ChangeLog.2000 | 1329 +++++ Documentation/ApplitudeWriters/Makefile | 10 + Documentation/ApplitudeWriters/appw.wml | 90 + Documentation/CellScroll/SCRATCH | 8 + Documentation/Clang_Design/Makefile | 11 + Documentation/Clang_Design/design.ptex | 456 ++ Documentation/Clang_Design/thales.wml | 187 + Documentation/CyberText/1.png | Bin 0 -> 3624 bytes Documentation/CyberText/3.png | Bin 0 -> 2527 bytes Documentation/CyberText/4.png | Bin 0 -> 4749 bytes Documentation/CyberText/Makefile | 11 + Documentation/CyberText/ct-old.wml | 911 ++++ Documentation/CyberText/ct.wml | 275 + Documentation/CyberText/email.dia | Bin 0 -> 3332 bytes Documentation/CyberText/kello-o.png | Bin 0 -> 14124 bytes Documentation/CyberText/kello.png | Bin 0 -> 8428 bytes Documentation/CyberText/permascroll.dia | Bin 0 -> 1291 bytes Documentation/CyberText/rank1vert.dia | 601 +++ Documentation/CyberText/rank2vert.dia | 375 ++ Documentation/CyberText/rank3both.dia | 745 +++ Documentation/CyberText/vilma.png | Bin 0 -> 3377 bytes Documentation/DesignProblems/Makefile | 11 + Documentation/DesignProblems/beamorder.dia | Bin 0 -> 743 bytes Documentation/DesignProblems/dp.wml | 680 +++ Documentation/DesignProblems/linkorder.dia | Bin 0 -> 677 bytes Documentation/DimBased/Makefile | 3 + Documentation/DimBased/dim.ptex | 53 + Documentation/FAQ | 262 + Documentation/Gentle_Introduction/Makefile | 19 + Documentation/Gentle_Introduction/README | 1 + Documentation/Gentle_Introduction/gi.wml | 586 +++ .../Gentle_Introduction/zzgentle.tex | 1280 +++++ Documentation/Glossary/Makefile | 10 + Documentation/Glossary/gl.wml | 186 + Documentation/Interfacing/Makefile | 6 + Documentation/Interfacing/int.ptex | 141 + Documentation/Makefile | 39 + Documentation/Math/Makefile | 3 + Documentation/Math/ajk-scribbles.tex | 60 + Documentation/Math/math.ptex | 110 + Documentation/Mediaserver/mediaserver.tex | 387 ++ Documentation/Networking/Makefile | 10 + Documentation/Networking/ZTP-usage.txt | 70 + Documentation/Networking/ZTP.txt | 161 + Documentation/Networking/mock-ZTPTCP.txt | 74 + Documentation/Networking/ztp.wml | 855 ++++ Documentation/Nile/Makefile | 14 + Documentation/Nile/nile.wml | 259 + Documentation/Nile/nileug.wml | 114 + Documentation/PROTOCOL | 192 + Documentation/README | 55 + Documentation/STARTING | 24 + Documentation/Slices/SliceLogic | 179 + Documentation/Slices/zzSliceLogic.jpg | Bin 0 -> 81225 bytes Documentation/Spec/Makefile | 15 + Documentation/Spec/canvasraster.dia | 427 ++ Documentation/Spec/cursor1.dia | 590 +++ Documentation/Spec/cursordim.dia | 769 +++ Documentation/Spec/email1.dia | 597 +++ Documentation/Spec/inheritparam.dia | 885 ++++ Documentation/Spec/rasterspec.dia | 678 +++ Documentation/Spec/zzspec.wml | 1127 +++++ Documentation/Syntaxless/synt.wml | 100 + Documentation/UsersGuide/Makefile | 15 + Documentation/UsersGuide/active.png | Bin 0 -> 4504 bytes Documentation/UsersGuide/addressbook.png | Bin 0 -> 4023 bytes Documentation/UsersGuide/aftermove.png | Bin 0 -> 3992 bytes Documentation/UsersGuide/alku.png | Bin 0 -> 2393 bytes Documentation/UsersGuide/bind1.png | Bin 0 -> 3010 bytes Documentation/UsersGuide/bind2.png | Bin 0 -> 3039 bytes Documentation/UsersGuide/boring.png | Bin 0 -> 2368 bytes Documentation/UsersGuide/bothwins.png | Bin 0 -> 22281 bytes Documentation/UsersGuide/breakkafka.png | Bin 0 -> 1747 bytes Documentation/UsersGuide/change1.png | Bin 0 -> 1753 bytes Documentation/UsersGuide/change2.png | Bin 0 -> 1819 bytes Documentation/UsersGuide/child1.png | Bin 0 -> 2438 bytes Documentation/UsersGuide/child2.png | Bin 0 -> 1833 bytes Documentation/UsersGuide/clone1.png | Bin 0 -> 16132 bytes Documentation/UsersGuide/clone2.png | Bin 0 -> 17101 bytes Documentation/UsersGuide/connect1.png | Bin 0 -> 14604 bytes Documentation/UsersGuide/connect2.png | Bin 0 -> 14787 bytes Documentation/UsersGuide/connection1.png | Bin 0 -> 2604 bytes Documentation/UsersGuide/creation.png | Bin 0 -> 2575 bytes Documentation/UsersGuide/dimensio.png | Bin 0 -> 2568 bytes Documentation/UsersGuide/edit1.png | Bin 0 -> 6886 bytes Documentation/UsersGuide/edit2.png | Bin 0 -> 6933 bytes Documentation/UsersGuide/edit3.png | Bin 0 -> 4634 bytes Documentation/UsersGuide/edit4.png | Bin 0 -> 4481 bytes Documentation/UsersGuide/extra.png | Bin 0 -> 2368 bytes Documentation/UsersGuide/f2.png | Bin 0 -> 2177 bytes Documentation/UsersGuide/familytree.png | Bin 0 -> 4310 bytes Documentation/UsersGuide/font.png | Bin 0 -> 1509 bytes Documentation/UsersGuide/grey.png | Bin 0 -> 2328 bytes Documentation/UsersGuide/hop1.png | Bin 0 -> 3036 bytes Documentation/UsersGuide/hop2.png | Bin 0 -> 3523 bytes Documentation/UsersGuide/hopolympos.png | Bin 0 -> 3020 bytes Documentation/UsersGuide/htree.png | Bin 0 -> 2236 bytes Documentation/UsersGuide/kafka.png | Bin 0 -> 1884 bytes Documentation/UsersGuide/klooni.png | Bin 0 -> 2811 bytes Documentation/UsersGuide/make1.png | Bin 0 -> 747 bytes Documentation/UsersGuide/make2.png | Bin 0 -> 1308 bytes Documentation/UsersGuide/make3.png | Bin 0 -> 1613 bytes Documentation/UsersGuide/make4.png | Bin 0 -> 1345 bytes Documentation/UsersGuide/make5.png | Bin 0 -> 2050 bytes Documentation/UsersGuide/make6.png | Bin 0 -> 1582 bytes Documentation/UsersGuide/margins.png | Bin 0 -> 1531 bytes Documentation/UsersGuide/mark1.png | Bin 0 -> 2569 bytes Documentation/UsersGuide/mark2.png | Bin 0 -> 2454 bytes Documentation/UsersGuide/markconnect.png | Bin 0 -> 2564 bytes Documentation/UsersGuide/mutsi.png | Bin 0 -> 2333 bytes Documentation/UsersGuide/mutsiosoite.png | Bin 0 -> 2875 bytes Documentation/UsersGuide/myspeech.png | Bin 0 -> 1260 bytes Documentation/UsersGuide/myspeech1.png | Bin 0 -> 1561 bytes Documentation/UsersGuide/myspeech2.png | Bin 0 -> 1769 bytes Documentation/UsersGuide/myspeech3.png | Bin 0 -> 1746 bytes Documentation/UsersGuide/newcells.png | Bin 0 -> 2459 bytes Documentation/UsersGuide/newstory.png | Bin 0 -> 5069 bytes Documentation/UsersGuide/newstory2.png | Bin 0 -> 5241 bytes Documentation/UsersGuide/newstory3.png | Bin 0 -> 6321 bytes Documentation/UsersGuide/newug.wml | 1222 +++++ Documentation/UsersGuide/olympos.png | Bin 0 -> 2554 bytes Documentation/UsersGuide/olympos2.png | Bin 0 -> 2230 bytes Documentation/UsersGuide/osoite.png | Bin 0 -> 2860 bytes Documentation/UsersGuide/para.png | Bin 0 -> 1308 bytes Documentation/UsersGuide/rainy.png | Bin 0 -> 2278 bytes Documentation/UsersGuide/rastererror.png | Bin 0 -> 2435 bytes Documentation/UsersGuide/rcfact1.png | Bin 0 -> 3539 bytes Documentation/UsersGuide/rightmoved.png | Bin 0 -> 24489 bytes Documentation/UsersGuide/rotate.png | Bin 0 -> 2564 bytes Documentation/UsersGuide/row.png | Bin 0 -> 1436 bytes Documentation/UsersGuide/shiny.png | Bin 0 -> 5211 bytes Documentation/UsersGuide/shinyhappy.png | Bin 0 -> 2256 bytes Documentation/UsersGuide/shinyhappy2.png | Bin 0 -> 2691 bytes Documentation/UsersGuide/shinyhappy3.png | Bin 0 -> 2150 bytes Documentation/UsersGuide/showingz.png | Bin 0 -> 7139 bytes Documentation/UsersGuide/start.png | Bin 0 -> 1045 bytes Documentation/UsersGuide/story.png | Bin 0 -> 753 bytes Documentation/UsersGuide/storytext.png | Bin 0 -> 4760 bytes Documentation/UsersGuide/structure1.png | Bin 0 -> 2350 bytes Documentation/UsersGuide/structure2.png | Bin 0 -> 2483 bytes Documentation/UsersGuide/suku.png | Bin 0 -> 1811 bytes Documentation/UsersGuide/testi.png | Bin 0 -> 2395 bytes Documentation/UsersGuide/ug.wml | 400 ++ Documentation/UsersGuide/wallstreet.png | Bin 0 -> 2630 bytes Documentation/UsersGuide/widthstr.png | Bin 0 -> 1590 bytes Documentation/UsersGuide/wrongconn.png | Bin 0 -> 2600 bytes Documentation/diagrams/Makefile | 5 + Documentation/diagrams/ZZCanvas.dia | Bin 0 -> 770 bytes Documentation/diagrams/cursoring.dia | Bin 0 -> 1282 bytes Documentation/index.html | 130 + Documentation/keybindings.wml | 182 + Documentation/lib.mk | 33 + Documentation/misc/ADDRESSING | 26 + Documentation/misc/Curseling | 46 + Documentation/misc/RENDERING | 37 + Documentation/misc/TORESOLVE | 8 + Documentation/misc/billow | 20 + Documentation/misc/byrokratiadoku | 169 + Documentation/misc/keys | 80 + Documentation/misc/textcloud | 250 + Documentation/wmlinc/art.css | 26 + Documentation/wmlinc/article.wml | 7 + Documentation/wmlinc/catart.wml | 56 + Documentation/wmlinc/common.wml | 117 + INSTALL | 5 + Java/.gvimrc | 2 + Java/ApplitudeMgr.java | 310 ++ Java/BuildInfo.java.in | 39 + Java/ChkVersion.java | 94 + Java/CommandLineOptionsParser.java | 311 ++ Java/Dump.java | 242 + Java/Dumper.java | 161 + Java/JEv.java | 73 + Java/LoopDetector.java | 66 + Java/Main.java | 535 ++ Java/Makefile | 185 + Java/NullZOb.java | 40 + Java/Package.html | 9 + Java/README | 146 + Java/RString.java | 41 + Java/SafeExit.java | 95 + Java/ScalableFont.java | 122 + Java/SoundObs.java | 37 + Java/SpaceDump.java | 164 + Java/SysLogger.java | 44 + Java/TODO | 155 + Java/TestSpace.java | 53 + Java/TimeTest.java | 155 + Java/UndoList.java | 220 + Java/ZOb.java | 39 + Java/ZTPCommand.java | 207 + Java/ZZCanvasView.java | 231 + Java/ZZCell.java | 719 +++ Java/ZZCellHandle.java | 81 + Java/ZZCommand.java | 84 + Java/ZZConnection.java | 62 + Java/ZZCursor.java | 70 + Java/ZZCursorReal.java | 367 ++ Java/ZZCursorVirtual.java | 61 + Java/ZZDefaultSpace.java | 1087 ++++ Java/ZZDimSpace.java | 442 ++ Java/ZZDimension.java | 178 + Java/ZZDrawing.java | 106 + Java/ZZEvObs.java | 36 + Java/ZZExec.java | 58 + Java/ZZIter.java | 162 + Java/ZZKeyBindings.java | 39 + Java/ZZKeyBindings0.java | 45 + Java/ZZKeyBindings1.java | 319 ++ Java/ZZKeyHacks.java | 105 + Java/ZZLocalDimension.java | 89 + Java/ZZLogger.java | 83 + Java/ZZModule.java | 91 + Java/ZZObs.java | 36 + Java/ZZObsTrigger.java | 196 + Java/ZZPath.java | 202 + Java/ZZPhotoView.java | 102 + Java/ZZPrimitiveActions.java | 1381 ++++++ Java/ZZPrimitiveCommand.zob | 59 + Java/ZZRODimension.java | 45 + Java/ZZScene.java | 74 + Java/ZZSlicedDimSpace.java | 116 + Java/ZZSpace.java | 319 ++ Java/ZZSpacePart.java | 95 + Java/ZZTextView.java | 106 + Java/ZZTraverseCB.java | 43 + Java/ZZUpdateManager.java | 253 + Java/ZZUtil.java | 575 +++ Java/ZZView.java | 63 + Java/ZZViewComponent.java | 287 ++ Java/ZZWindows.java | 231 + Java/arch/java2d/ZZDrawingJ2D.java | 167 + Java/arch/javadoc/ZobDoc.java | 154 + Java/arch/syslog/arch.mk | 19 + Java/arch/syslog/org_gzigzag_SysLogger.c | 46 + Java/check.pl | 26 + Java/clang/Data.java | 130 + Java/clang/ZZClang1.java | 186 + Java/clang/ZZClangContext.java | 95 + Java/clang/ZZClangContextReal.java | 56 + Java/clang/ZZClangContextVirtual.java | 60 + Java/clang/ZZClangOp.java | 59 + Java/clang/ZZClangOps.pl | 144 + Java/clang/flowing/B.java | 99 + Java/clang/flowing/C.java | 115 + Java/clang/flowing/Flowing.java | 260 + Java/clang/flowing/FlowingClang.java | 219 + Java/clang/flowing/Primitive.java | 64 + Java/clang/flowing/PrimitiveSet.java | 34 + Java/clang/flowing/StackFrame.java | 117 + Java/clang/flowing/StackFrameReal.java | 97 + Java/clang/flowing/StackFrameVirtual.java | 63 + Java/clang/flowing/T.java | 229 + Java/clang/flowing/X.java | 138 + Java/clang/heraclitus/HeraclitusClang.java | 108 + Java/clang/heraclitus/HeraclitusCommand.zob | 79 + Java/clang/heraclitus/PS1.java | 85 + Java/clang/heraclitus/Primitive.java | 41 + Java/clang/heraclitus/PrimitiveSet.java | 34 + Java/clang/thales/DimensionNames.java | 52 + Java/clang/thales/Environment.java | 109 + Java/clang/thales/Evaluator.java | 62 + Java/clang/thales/PrimitiveOperation.java | 32 + Java/clang/thales/README | 4 + Java/clang/thales/Refcounted.java | 28 + Java/clang/thales/SyntaxForm.java | 168 + Java/clang/thales/Task.java | 81 + Java/clang/thales/ThalesClang.java | 46 + Java/clang/thales/ThalesProgram.zob | 45 + Java/clang/thales/primitives/If.java | 28 + .../clang/thales/syntaxforms/Abstraction.java | 55 + .../clang/thales/syntaxforms/CellDenoter.java | 82 + .../clang/thales/syntaxforms/CellLiteral.java | 75 + Java/clang/thales/syntaxforms/Primitive.java | 191 + Java/clang/thales/syntaxforms/Sequence.java | 95 + Java/d.java | 47 + Java/dump2java.pl | 147 + Java/errors/MissingTermError.java | 30 + Java/errors/SyntaxError.java | 28 + Java/errors/ZZConnectWouldBreakError.java | 34 + Java/errors/ZZError.java | 42 + Java/errors/ZZFatalError.java | 40 + Java/errors/ZZInfiniteLoop.java | 33 + Java/errors/ZZInvalidCursorPositionError.java | 34 + Java/errors/ZZInvalidDimensionError.java | 33 + Java/exp/rast/vanishing.view | 107 + Java/flob/ArrowDecor.java | 134 + Java/flob/BallCell.java | 159 + Java/flob/BeamDecor.java | 107 + Java/flob/BoxType.java | 90 + Java/flob/BoxedFlob.java | 83 + Java/flob/CellBgFlob.java | 118 + Java/flob/CellFlob1.java | 105 + Java/flob/CellFlobFactory1.zob | 205 + Java/flob/CellFlobFactory2.zob | 207 + Java/flob/Colorer.java | 41 + Java/flob/CombinedView.zob | 58 + Java/flob/CompassView.zob | 149 + Java/flob/ConnectionLineDecor.java | 174 + Java/flob/CoordDecor.java | 122 + Java/flob/CursorView.zob | 218 + Java/flob/FTextCellView.zob | 179 + Java/flob/FTextLayouter.zob | 253 + Java/flob/Flob.java | 202 + Java/flob/FlobDecorator.java | 39 + Java/flob/FlobFactory.java | 89 + Java/flob/FlobSet.java | 521 ++ Java/flob/FlobView.java | 57 + Java/flob/GridGeom.java | 51 + Java/flob/ICView.zob | 71 + Java/flob/IdiosyncraticFlobFactory.zob | 98 + Java/flob/Level.java | 193 + Java/flob/LevelView.zob | 492 ++ Java/flob/LineDecor.java | 101 + Java/flob/MagGrid.zob | 112 + Java/flob/ManyToManyView.zob | 282 ++ Java/flob/MultiView.zob | 90 + Java/flob/NullView.zob | 41 + Java/flob/ParallelTextView.zob | 138 + Java/flob/RankTextView.zob | 307 ++ Java/flob/Renderable.java | 88 + Java/flob/RowColView.zob | 125 + Java/flob/SceneFlob.java | 148 + Java/flob/SimpleBeamer.zob | 256 + Java/flob/SimpleBoxType.java | 66 + Java/flob/SimpleFlobConnector.zob | 109 + Java/flob/SimpleFlobView.zob | 153 + Java/flob/SimpleSceneFlob.java | 88 + Java/flob/SimpleTextView.zob | 84 + Java/flob/SpanFlob.java | 58 + Java/flob/SplitCellFlob1.java | 354 ++ Java/flob/SplitView.zob | 78 + Java/flob/StdLinks.zob | 208 + Java/flob/TextDecor.java | 73 + Java/flob/TreeView.zob | 492 ++ Java/flob/VanishingView.zob | 317 ++ Java/flob/VobSet.java | 73 + Java/flob/WindowCellView.zob | 129 + Java/media/Address.java | 95 + Java/media/ByteScroll.java | 99 + Java/media/Capitalizer.java | 100 + Java/media/CharScroll.java | 109 + Java/media/FText.java | 226 + Java/media/FirstMatchBreaker.java | 143 + Java/media/LineBreaker.java | 112 + Java/media/LineInfo.java | 55 + Java/media/README | 2 + Java/media/Scroll.java | 97 + Java/media/SimpleLineBreaker.java | 141 + Java/media/SimpleLineInfo.java | 91 + Java/media/SoundScroll.java | 63 + Java/media/Span.java | 178 + Java/media/SpanSet.java | 45 + Java/media/SpanTree.java | 54 + Java/media/Stream.java | 289 ++ Java/media/StringScroll.java | 310 ++ Java/media/TestLines.java | 189 + Java/media/UTF8Char.java | 245 + Java/media/VStream.java | 655 +++ Java/media/ZZDefaultText.java | 100 + Java/media/ZZHumber.java | 57 + Java/media/ZZSoundView.java | 115 + Java/media/ZZText.java | 117 + Java/mungencss.pl | 9 + Java/net/Peer.java | 61 + Java/net/ReliableUDPMessage.java | 71 + Java/net/ReliableUDPMessageFactory.java | 40 + Java/net/ReliableUDPSocket.java | 321 ++ Java/p2p/P2PStorage.java | 82 + Java/p2p/UniqueID.java | 54 + Java/part/BinaryTreePart.java | 100 + Java/part/DoubleStepPart.java | 64 + Java/part/GenTreePart.java | 160 + Java/part/GenTreePartModel.java | 77 + Java/part/GenTreeTestModel.java | 83 + Java/part/ImpliedTreePart.java | 173 + Java/part/ImpliedTreePart2.java | 192 + Java/part/VersionPart.java | 634 +++ Java/part/ZZROSpacePart.java | 39 + Java/part/ZZROStrSpacePart.java | 47 + Java/script/Makefile | 53 + Java/script/ZZId.h | 12 + Java/script/ZZScriptAPI_1_JNI.cpp | 31 + Java/script/ZZScriptAPI_1_JNI.h | 131 + Java/script/ZZScriptPerl.cpp | 55 + Java/script/ZZScriptPerl.java | 9 + Java/script/invoke.c | 76 + Java/storage/ContentStore.java | 35 + Java/storage/ContentStorer.java | 36 + Java/storage/CountingStream.java | 71 + Java/storage/DimStore.java | 33 + Java/storage/DirStreamSet.java | 91 + Java/storage/DummyStreamSet.java | 50 + Java/storage/FileWritable.java | 251 + Java/storage/Flushable.java | 39 + Java/storage/GZZ0.java | 191 + Java/storage/MemWritable.java | 76 + Java/storage/Recs.pl | 232 + Java/storage/SimpleContentFile.java | 129 + Java/storage/SimpleDimFile.java | 137 + Java/storage/Sliced.java | 87 + Java/storage/SlicedCursor.java | 149 + Java/storage/SlicedHomes.java | 59 + Java/storage/SlicedSame.java | 50 + Java/storage/StreamSet.java | 63 + Java/storage/Writable.java | 37 + Java/storage/ZZCacheContentStore.java | 122 + Java/storage/ZZCacheDimSpace.java | 249 + Java/storage/ZZCacheDimension.java | 281 ++ Java/storage/ZZDimStorer.java | 47 + Java/transform/ChangeDim.java | 58 + Java/transform/ClearDim.java | 55 + Java/transform/CopyDim.java | 58 + Java/transform/FoldDim.java | 76 + Java/transform/ReverseDim.java | 96 + Java/transform/Version0.java | 66 + Java/transform/Version1.java | 56 + Java/transform/Version2.java | 44 + Java/transform/VersionChanger.java | 37 + Java/zob2java.pl | 302 ++ LICENSE.lgpl | 481 ++ LICENSE.xpl | 16 + Makefile | 97 + Manifest | 599 +++ Modules/README | 19 + Modules/applet/ZZApplet.java | 42 + Modules/applet/example1.html | 12 + Modules/awtool/AwtCursor.java | 36 + Modules/awtool/AwtLink.java | 176 + Modules/awtool/AwtLink.zob | 80 + Modules/awtool/AwtMetrics.java | 502 ++ Modules/awtool/AwtMetrics.zob | 326 ++ Modules/awtool/AwtMetricsFC.java | 94 + Modules/awtool/AwtMetricsFC2.java | 94 + Modules/awtool/AwtMetricsNormal.java | 58 + Modules/awtool/AwtNileView.java | 110 + Modules/awtool/AwtNote.java | 212 + Modules/awtool/AwtNote.zob | 135 + Modules/awtool/AwtUtil.java | 329 ++ Modules/awtool/AwtView1.java | 341 ++ Modules/awtool/Awtool.java | 1016 ++++ Modules/awtool/Awtool.zob | 955 ++++ Modules/awtool/BooleanMesh.java | 78 + Modules/awtool/README | 58 + Modules/awtool/TODO | 14 + Modules/awtool/ZObCellRepr.java | 57 + Modules/benchmark/GraphBench.java | 126 + Modules/benchmark/README | 16 + Modules/benchmark/ZZBench.java | 100 + Modules/benchmark/java2d/Java2DBench.java | 95 + Modules/database/DB0.java | 227 + Modules/database/createscript.pl | 68 + Modules/database/zz.queries | 18 + Modules/database/zz.sql | 29 + Modules/daytimedemo/Calendar2.zob | 162 + Modules/daytimedemo/ClockCellView.zob | 116 + Modules/daytimedemo/DayTimeDemo.zob | 174 + Modules/extern/Extern.java | 83 + Modules/hypergenealogy/HyperGenealogy.zob | 283 ++ Modules/iter/DimRecursor.java | 117 + Modules/iter/EnumVanishingView.zob | 177 + Modules/iter/Iter.java | 212 + Modules/iter/README | 1 + Modules/joystick/LinuxJoystick.java | 91 + Modules/mbox/SingleMail.zob | 133 + Modules/mbox/ZZDateParser.java | 398 ++ Modules/mbox/ZZMbox.java | 742 +++ Modules/mind/Mind.java | 191 + Modules/mind/MindSun.java | 398 ++ Modules/mind/MindSundew.java | 247 + Modules/multimedia/Default.java | 40 + Modules/multimedia/MediaFlobFactory.java | 189 + Modules/multimedia/MediaFlobView.java | 40 + Modules/multimedia/MediaMath.java | 460 ++ Modules/multimedia/MediaZOb.java | 216 + Modules/multimedia/Pixels.java | 163 + Modules/multimedia/PolygonRenderer.java | 61 + Modules/multimedia/Polygons.java | 65 + Modules/multimedia/adjust.java | 109 + Modules/multimedia/crop.java | 94 + Modules/multimedia/dots.java | 58 + Modules/multimedia/image.java | 102 + Modules/multimedia/mm.java | 51 + Modules/multimedia/move.java | 70 + Modules/multimedia/readme.html | 107 + Modules/multimedia/rect.java | 122 + Modules/multimedia/sin.java | 42 + Modules/nile/Nile1.java | 327 ++ Modules/nile/Nile1Div.java | 71 + Modules/nile/Nile1GenTreeModel.java | 81 + Modules/nile/Nile1Ops.java | 479 ++ Modules/nile/Nile1Text.java | 356 ++ Modules/nile/Nile1View.zob | 311 ++ Modules/nile/Nile2Iter.java | 589 +++ Modules/nile/Nile2Ops.java | 254 + Modules/nile/Nile2Test.java | 152 + Modules/nile/Nile2Unit.java | 432 ++ Modules/nile/NileApplet.java | 63 + Modules/nile/NileDemo.java | 143 + Modules/nile/README | 49 + Modules/nile/SplitNileDemo.java | 113 + Modules/nile/SplitNileView.zob | 71 + Modules/nile/draft/Nile3Ops.java | 166 + Modules/nile/draft/Nile3Part.java | 132 + Modules/nile/draft/Nile3Pos.java | 338 ++ Modules/nile/draft/Nile3Unit.java | 305 ++ Modules/notemap/Notemap.zob | 212 + Modules/openGL/Makefile | 22 + Modules/openGL/OpenGLCloud.java | 133 + Modules/openGL/ZZOpenGLGraphics.cc | 474 ++ Modules/openGL/ZZOpenGLGraphics.java | 606 +++ .../openGL/fi_iki_lukka_ZZOpenGLGraphics.h | 125 + Modules/panes/PaneView.zob | 76 + Modules/prez/Prez.java | 51 + Modules/prez/PrezRaster.zob | 173 + Modules/servlet/VCServlet.java | 144 + Modules/servlet/ZZServlet.java | 78 + Modules/servlet/startjetty | 4 + Modules/servlet/zzserv.prp | 42 + Modules/servlet/zzserv2.prp | 205 + Modules/sound/Player.java | 37 + Modules/sound/Recorder.java | 37 + Modules/sound/SimplePlayer.java | 65 + Modules/sound/SimpleRecorder.java | 68 + Modules/sound/Sound.java | 373 ++ Modules/sound/gsm_def.h | 2 + Modules/sound/gsm_player.c | 247 + Modules/sound/gsm_recorder.c | 240 + .../sound/org_gzigzag_module_SimplePlayer.h | 45 + .../sound/org_gzigzag_module_SimpleRecorder.h | 45 + Modules/test/README | 2 + Modules/test/TestClang1.java | 100 + Modules/test/TestHuge.java | 55 + Modules/test/TestUndo.java | 210 + Modules/textcloud/TextCloud.zob | 353 ++ .../virtualcommunity/MessageFlobFactory.zob | 546 ++ Modules/virtualcommunity/VCView1.java | 377 ++ Modules/virtualcommunity/VCView2.java | 263 + Modules/virtualcommunity/VCView3.java | 242 + Modules/virtualcommunity/VCView4.java | 141 + Modules/virtualcommunity/VirtualCommunity.zob | 444 ++ Modules/vob/Connection.java | 47 + Modules/vob/View.java | 38 + Modules/vob/Vob.java | 142 + Modules/vob/VobSet.java | 66 + Modules/vob/VobStore.java | 64 + Modules/wordnet/conv.pl | 160 + Modules/xml/XML.java | 276 ++ Modules/xml/old2xml.pl | 241 + Modules/zaubertrank/README.html | 111 + Modules/zaubertrank/TokenTextCellView.java | 65 + Modules/zaubertrank/ZaubertrankCellView.java | 141 + Modules/zaubertrank/old/Actions.java | 256 + Modules/zaubertrank/old/Evaluator.java | 93 + Modules/zaubertrank/old/ParsedView.zob | 209 + Modules/zaubertrank/old/Parser.java | 275 + Modules/zaubertrank/old/Primitive.java | 43 + Modules/zaubertrank/old/PrimitiveSet.java | 78 + Modules/zaubertrank/old/SimpleView.zob | 137 + Modules/zaubertrank/old/TokenFlob.java | 78 + Modules/zaubertrank/old/TokenGrouper.java | 81 + Modules/zaubertrank/old/Zaubertrank.java | 54 + Modules/zaubertrank/old/ZaubertrankPart.java | 216 + Modules/ztp/ZTPclient.java | 71 + Modules/ztp/ZTPserver.java | 82 + Modules/ztp/client/Action.java | 29 + Modules/ztp/client/Get.java | 43 + Modules/ztp/client/Put.java | 43 + Modules/ztp/client/RemotePieceData.zob | 64 + Modules/ztp/client/Response.java | 76 + Modules/ztp/client/Session.java | 165 + Modules/ztp/client/Subspace.java | 76 + Modules/ztp/common/LineBufferedIO.java | 111 + Modules/ztp/common/SubspaceDump.java | 134 + Modules/ztp/server/GetMessage.java | 112 + Modules/ztp/server/Listener.java | 55 + Modules/ztp/server/PutMessage.java | 117 + Modules/ztp/server/Session.java | 227 + Modules/ztp/server/UserManager.java | 139 + Modules/ztp/server/UserRecord.zob | 56 + NEWS | 207 + Perl/PerlServImpl.pm | 63 + Perl/README | 5 + Perl/ZZPerlDBServ.pm | 137 + Perl/ZZPerlServ.pm | 410 ++ Perl/ZZPerlSimpleClient.pm | 111 + Perl/cperl.pl | 33 + Perl/sperl.pl | 28 + README | 65 + VERSION | 1 + changelog-authors | 10 + cvsparser.pl | 36 + makedist.param | 2 + makedist.sh | 73 + manifest-filter.lst | 4 + manifest-filter.pl | 24 + md5sum | 599 +++ 600 files changed, 87187 insertions(+) create mode 100644 C++/README create mode 100644 CODING create mode 100644 ChangeLog create mode 100644 ChangeLog.2000 create mode 100644 Documentation/ApplitudeWriters/Makefile create mode 100644 Documentation/ApplitudeWriters/appw.wml create mode 100644 Documentation/CellScroll/SCRATCH create mode 100644 Documentation/Clang_Design/Makefile create mode 100644 Documentation/Clang_Design/design.ptex create mode 100644 Documentation/Clang_Design/thales.wml create mode 100644 Documentation/CyberText/1.png create mode 100644 Documentation/CyberText/3.png create mode 100644 Documentation/CyberText/4.png create mode 100644 Documentation/CyberText/Makefile create mode 100644 Documentation/CyberText/ct-old.wml create mode 100644 Documentation/CyberText/ct.wml create mode 100644 Documentation/CyberText/email.dia create mode 100644 Documentation/CyberText/kello-o.png create mode 100644 Documentation/CyberText/kello.png create mode 100644 Documentation/CyberText/permascroll.dia create mode 100644 Documentation/CyberText/rank1vert.dia create mode 100644 Documentation/CyberText/rank2vert.dia create mode 100644 Documentation/CyberText/rank3both.dia create mode 100644 Documentation/CyberText/vilma.png create mode 100644 Documentation/DesignProblems/Makefile create mode 100644 Documentation/DesignProblems/beamorder.dia create mode 100644 Documentation/DesignProblems/dp.wml create mode 100644 Documentation/DesignProblems/linkorder.dia create mode 100644 Documentation/DimBased/Makefile create mode 100644 Documentation/DimBased/dim.ptex create mode 100644 Documentation/FAQ create mode 100644 Documentation/Gentle_Introduction/Makefile create mode 100644 Documentation/Gentle_Introduction/README create mode 100644 Documentation/Gentle_Introduction/gi.wml create mode 100644 Documentation/Gentle_Introduction/zzgentle.tex create mode 100644 Documentation/Glossary/Makefile create mode 100644 Documentation/Glossary/gl.wml create mode 100644 Documentation/Interfacing/Makefile create mode 100644 Documentation/Interfacing/int.ptex create mode 100644 Documentation/Makefile create mode 100644 Documentation/Math/Makefile create mode 100644 Documentation/Math/ajk-scribbles.tex create mode 100644 Documentation/Math/math.ptex create mode 100644 Documentation/Mediaserver/mediaserver.tex create mode 100644 Documentation/Networking/Makefile create mode 100644 Documentation/Networking/ZTP-usage.txt create mode 100644 Documentation/Networking/ZTP.txt create mode 100644 Documentation/Networking/mock-ZTPTCP.txt create mode 100644 Documentation/Networking/ztp.wml create mode 100644 Documentation/Nile/Makefile create mode 100644 Documentation/Nile/nile.wml create mode 100644 Documentation/Nile/nileug.wml create mode 100644 Documentation/PROTOCOL create mode 100644 Documentation/README create mode 100644 Documentation/STARTING create mode 100644 Documentation/Slices/SliceLogic create mode 100644 Documentation/Slices/zzSliceLogic.jpg create mode 100644 Documentation/Spec/Makefile create mode 100644 Documentation/Spec/canvasraster.dia create mode 100644 Documentation/Spec/cursor1.dia create mode 100644 Documentation/Spec/cursordim.dia create mode 100644 Documentation/Spec/email1.dia create mode 100644 Documentation/Spec/inheritparam.dia create mode 100644 Documentation/Spec/rasterspec.dia create mode 100644 Documentation/Spec/zzspec.wml create mode 100644 Documentation/Syntaxless/synt.wml create mode 100644 Documentation/UsersGuide/Makefile create mode 100644 Documentation/UsersGuide/active.png create mode 100644 Documentation/UsersGuide/addressbook.png create mode 100644 Documentation/UsersGuide/aftermove.png create mode 100644 Documentation/UsersGuide/alku.png create mode 100644 Documentation/UsersGuide/bind1.png create mode 100644 Documentation/UsersGuide/bind2.png create mode 100644 Documentation/UsersGuide/boring.png create mode 100644 Documentation/UsersGuide/bothwins.png create mode 100644 Documentation/UsersGuide/breakkafka.png create mode 100644 Documentation/UsersGuide/change1.png create mode 100644 Documentation/UsersGuide/change2.png create mode 100644 Documentation/UsersGuide/child1.png create mode 100644 Documentation/UsersGuide/child2.png create mode 100644 Documentation/UsersGuide/clone1.png create mode 100644 Documentation/UsersGuide/clone2.png create mode 100644 Documentation/UsersGuide/connect1.png create mode 100644 Documentation/UsersGuide/connect2.png create mode 100644 Documentation/UsersGuide/connection1.png create mode 100644 Documentation/UsersGuide/creation.png create mode 100644 Documentation/UsersGuide/dimensio.png create mode 100644 Documentation/UsersGuide/edit1.png create mode 100644 Documentation/UsersGuide/edit2.png create mode 100644 Documentation/UsersGuide/edit3.png create mode 100644 Documentation/UsersGuide/edit4.png create mode 100644 Documentation/UsersGuide/extra.png create mode 100644 Documentation/UsersGuide/f2.png create mode 100644 Documentation/UsersGuide/familytree.png create mode 100644 Documentation/UsersGuide/font.png create mode 100644 Documentation/UsersGuide/grey.png create mode 100644 Documentation/UsersGuide/hop1.png create mode 100644 Documentation/UsersGuide/hop2.png create mode 100644 Documentation/UsersGuide/hopolympos.png create mode 100644 Documentation/UsersGuide/htree.png create mode 100644 Documentation/UsersGuide/kafka.png create mode 100644 Documentation/UsersGuide/klooni.png create mode 100644 Documentation/UsersGuide/make1.png create mode 100644 Documentation/UsersGuide/make2.png create mode 100644 Documentation/UsersGuide/make3.png create mode 100644 Documentation/UsersGuide/make4.png create mode 100644 Documentation/UsersGuide/make5.png create mode 100644 Documentation/UsersGuide/make6.png create mode 100644 Documentation/UsersGuide/margins.png create mode 100644 Documentation/UsersGuide/mark1.png create mode 100644 Documentation/UsersGuide/mark2.png create mode 100644 Documentation/UsersGuide/markconnect.png create mode 100644 Documentation/UsersGuide/mutsi.png create mode 100644 Documentation/UsersGuide/mutsiosoite.png create mode 100644 Documentation/UsersGuide/myspeech.png create mode 100644 Documentation/UsersGuide/myspeech1.png create mode 100644 Documentation/UsersGuide/myspeech2.png create mode 100644 Documentation/UsersGuide/myspeech3.png create mode 100644 Documentation/UsersGuide/newcells.png create mode 100644 Documentation/UsersGuide/newstory.png create mode 100644 Documentation/UsersGuide/newstory2.png create mode 100644 Documentation/UsersGuide/newstory3.png create mode 100644 Documentation/UsersGuide/newug.wml create mode 100644 Documentation/UsersGuide/olympos.png create mode 100644 Documentation/UsersGuide/olympos2.png create mode 100644 Documentation/UsersGuide/osoite.png create mode 100644 Documentation/UsersGuide/para.png create mode 100644 Documentation/UsersGuide/rainy.png create mode 100644 Documentation/UsersGuide/rastererror.png create mode 100644 Documentation/UsersGuide/rcfact1.png create mode 100644 Documentation/UsersGuide/rightmoved.png create mode 100644 Documentation/UsersGuide/rotate.png create mode 100644 Documentation/UsersGuide/row.png create mode 100644 Documentation/UsersGuide/shiny.png create mode 100644 Documentation/UsersGuide/shinyhappy.png create mode 100644 Documentation/UsersGuide/shinyhappy2.png create mode 100644 Documentation/UsersGuide/shinyhappy3.png create mode 100644 Documentation/UsersGuide/showingz.png create mode 100644 Documentation/UsersGuide/start.png create mode 100644 Documentation/UsersGuide/story.png create mode 100644 Documentation/UsersGuide/storytext.png create mode 100644 Documentation/UsersGuide/structure1.png create mode 100644 Documentation/UsersGuide/structure2.png create mode 100644 Documentation/UsersGuide/suku.png create mode 100644 Documentation/UsersGuide/testi.png create mode 100644 Documentation/UsersGuide/ug.wml create mode 100644 Documentation/UsersGuide/wallstreet.png create mode 100644 Documentation/UsersGuide/widthstr.png create mode 100644 Documentation/UsersGuide/wrongconn.png create mode 100644 Documentation/diagrams/Makefile create mode 100644 Documentation/diagrams/ZZCanvas.dia create mode 100644 Documentation/diagrams/cursoring.dia create mode 100644 Documentation/index.html create mode 100644 Documentation/keybindings.wml create mode 100644 Documentation/lib.mk create mode 100644 Documentation/misc/ADDRESSING create mode 100644 Documentation/misc/Curseling create mode 100644 Documentation/misc/RENDERING create mode 100644 Documentation/misc/TORESOLVE create mode 100644 Documentation/misc/billow create mode 100644 Documentation/misc/byrokratiadoku create mode 100644 Documentation/misc/keys create mode 100644 Documentation/misc/textcloud create mode 100644 Documentation/wmlinc/art.css create mode 100644 Documentation/wmlinc/article.wml create mode 100644 Documentation/wmlinc/catart.wml create mode 100644 Documentation/wmlinc/common.wml create mode 100644 INSTALL create mode 100644 Java/.gvimrc create mode 100644 Java/ApplitudeMgr.java create mode 100644 Java/BuildInfo.java.in create mode 100644 Java/ChkVersion.java create mode 100644 Java/CommandLineOptionsParser.java create mode 100644 Java/Dump.java create mode 100644 Java/Dumper.java create mode 100644 Java/JEv.java create mode 100644 Java/LoopDetector.java create mode 100644 Java/Main.java create mode 100644 Java/Makefile create mode 100644 Java/NullZOb.java create mode 100644 Java/Package.html create mode 100644 Java/README create mode 100644 Java/RString.java create mode 100644 Java/SafeExit.java create mode 100644 Java/ScalableFont.java create mode 100644 Java/SoundObs.java create mode 100644 Java/SpaceDump.java create mode 100644 Java/SysLogger.java create mode 100644 Java/TODO create mode 100644 Java/TestSpace.java create mode 100644 Java/TimeTest.java create mode 100644 Java/UndoList.java create mode 100644 Java/ZOb.java create mode 100644 Java/ZTPCommand.java create mode 100644 Java/ZZCanvasView.java create mode 100644 Java/ZZCell.java create mode 100644 Java/ZZCellHandle.java create mode 100644 Java/ZZCommand.java create mode 100644 Java/ZZConnection.java create mode 100644 Java/ZZCursor.java create mode 100644 Java/ZZCursorReal.java create mode 100644 Java/ZZCursorVirtual.java create mode 100644 Java/ZZDefaultSpace.java create mode 100644 Java/ZZDimSpace.java create mode 100644 Java/ZZDimension.java create mode 100644 Java/ZZDrawing.java create mode 100644 Java/ZZEvObs.java create mode 100644 Java/ZZExec.java create mode 100644 Java/ZZIter.java create mode 100644 Java/ZZKeyBindings.java create mode 100644 Java/ZZKeyBindings0.java create mode 100644 Java/ZZKeyBindings1.java create mode 100644 Java/ZZKeyHacks.java create mode 100644 Java/ZZLocalDimension.java create mode 100644 Java/ZZLogger.java create mode 100644 Java/ZZModule.java create mode 100644 Java/ZZObs.java create mode 100644 Java/ZZObsTrigger.java create mode 100644 Java/ZZPath.java create mode 100644 Java/ZZPhotoView.java create mode 100644 Java/ZZPrimitiveActions.java create mode 100644 Java/ZZPrimitiveCommand.zob create mode 100644 Java/ZZRODimension.java create mode 100644 Java/ZZScene.java create mode 100644 Java/ZZSlicedDimSpace.java create mode 100644 Java/ZZSpace.java create mode 100644 Java/ZZSpacePart.java create mode 100644 Java/ZZTextView.java create mode 100644 Java/ZZTraverseCB.java create mode 100644 Java/ZZUpdateManager.java create mode 100644 Java/ZZUtil.java create mode 100644 Java/ZZView.java create mode 100644 Java/ZZViewComponent.java create mode 100644 Java/ZZWindows.java create mode 100644 Java/arch/java2d/ZZDrawingJ2D.java create mode 100644 Java/arch/javadoc/ZobDoc.java create mode 100644 Java/arch/syslog/arch.mk create mode 100644 Java/arch/syslog/org_gzigzag_SysLogger.c create mode 100644 Java/check.pl create mode 100644 Java/clang/Data.java create mode 100644 Java/clang/ZZClang1.java create mode 100644 Java/clang/ZZClangContext.java create mode 100644 Java/clang/ZZClangContextReal.java create mode 100644 Java/clang/ZZClangContextVirtual.java create mode 100644 Java/clang/ZZClangOp.java create mode 100644 Java/clang/ZZClangOps.pl create mode 100644 Java/clang/flowing/B.java create mode 100644 Java/clang/flowing/C.java create mode 100644 Java/clang/flowing/Flowing.java create mode 100644 Java/clang/flowing/FlowingClang.java create mode 100644 Java/clang/flowing/Primitive.java create mode 100644 Java/clang/flowing/PrimitiveSet.java create mode 100644 Java/clang/flowing/StackFrame.java create mode 100644 Java/clang/flowing/StackFrameReal.java create mode 100644 Java/clang/flowing/StackFrameVirtual.java create mode 100644 Java/clang/flowing/T.java create mode 100644 Java/clang/flowing/X.java create mode 100644 Java/clang/heraclitus/HeraclitusClang.java create mode 100644 Java/clang/heraclitus/HeraclitusCommand.zob create mode 100644 Java/clang/heraclitus/PS1.java create mode 100644 Java/clang/heraclitus/Primitive.java create mode 100644 Java/clang/heraclitus/PrimitiveSet.java create mode 100644 Java/clang/thales/DimensionNames.java create mode 100644 Java/clang/thales/Environment.java create mode 100644 Java/clang/thales/Evaluator.java create mode 100644 Java/clang/thales/PrimitiveOperation.java create mode 100644 Java/clang/thales/README create mode 100644 Java/clang/thales/Refcounted.java create mode 100644 Java/clang/thales/SyntaxForm.java create mode 100644 Java/clang/thales/Task.java create mode 100644 Java/clang/thales/ThalesClang.java create mode 100644 Java/clang/thales/ThalesProgram.zob create mode 100644 Java/clang/thales/primitives/If.java create mode 100644 Java/clang/thales/syntaxforms/Abstraction.java create mode 100644 Java/clang/thales/syntaxforms/CellDenoter.java create mode 100644 Java/clang/thales/syntaxforms/CellLiteral.java create mode 100644 Java/clang/thales/syntaxforms/Primitive.java create mode 100644 Java/clang/thales/syntaxforms/Sequence.java create mode 100644 Java/d.java create mode 100644 Java/dump2java.pl create mode 100644 Java/errors/MissingTermError.java create mode 100644 Java/errors/SyntaxError.java create mode 100644 Java/errors/ZZConnectWouldBreakError.java create mode 100644 Java/errors/ZZError.java create mode 100644 Java/errors/ZZFatalError.java create mode 100644 Java/errors/ZZInfiniteLoop.java create mode 100644 Java/errors/ZZInvalidCursorPositionError.java create mode 100644 Java/errors/ZZInvalidDimensionError.java create mode 100644 Java/exp/rast/vanishing.view create mode 100644 Java/flob/ArrowDecor.java create mode 100644 Java/flob/BallCell.java create mode 100644 Java/flob/BeamDecor.java create mode 100644 Java/flob/BoxType.java create mode 100644 Java/flob/BoxedFlob.java create mode 100644 Java/flob/CellBgFlob.java create mode 100644 Java/flob/CellFlob1.java create mode 100644 Java/flob/CellFlobFactory1.zob create mode 100644 Java/flob/CellFlobFactory2.zob create mode 100644 Java/flob/Colorer.java create mode 100644 Java/flob/CombinedView.zob create mode 100644 Java/flob/CompassView.zob create mode 100644 Java/flob/ConnectionLineDecor.java create mode 100644 Java/flob/CoordDecor.java create mode 100644 Java/flob/CursorView.zob create mode 100644 Java/flob/FTextCellView.zob create mode 100644 Java/flob/FTextLayouter.zob create mode 100644 Java/flob/Flob.java create mode 100644 Java/flob/FlobDecorator.java create mode 100644 Java/flob/FlobFactory.java create mode 100644 Java/flob/FlobSet.java create mode 100644 Java/flob/FlobView.java create mode 100644 Java/flob/GridGeom.java create mode 100644 Java/flob/ICView.zob create mode 100644 Java/flob/IdiosyncraticFlobFactory.zob create mode 100644 Java/flob/Level.java create mode 100644 Java/flob/LevelView.zob create mode 100644 Java/flob/LineDecor.java create mode 100644 Java/flob/MagGrid.zob create mode 100644 Java/flob/ManyToManyView.zob create mode 100644 Java/flob/MultiView.zob create mode 100644 Java/flob/NullView.zob create mode 100644 Java/flob/ParallelTextView.zob create mode 100644 Java/flob/RankTextView.zob create mode 100644 Java/flob/Renderable.java create mode 100644 Java/flob/RowColView.zob create mode 100644 Java/flob/SceneFlob.java create mode 100644 Java/flob/SimpleBeamer.zob create mode 100644 Java/flob/SimpleBoxType.java create mode 100644 Java/flob/SimpleFlobConnector.zob create mode 100644 Java/flob/SimpleFlobView.zob create mode 100644 Java/flob/SimpleSceneFlob.java create mode 100644 Java/flob/SimpleTextView.zob create mode 100644 Java/flob/SpanFlob.java create mode 100644 Java/flob/SplitCellFlob1.java create mode 100644 Java/flob/SplitView.zob create mode 100644 Java/flob/StdLinks.zob create mode 100644 Java/flob/TextDecor.java create mode 100644 Java/flob/TreeView.zob create mode 100644 Java/flob/VanishingView.zob create mode 100644 Java/flob/VobSet.java create mode 100644 Java/flob/WindowCellView.zob create mode 100644 Java/media/Address.java create mode 100644 Java/media/ByteScroll.java create mode 100644 Java/media/Capitalizer.java create mode 100644 Java/media/CharScroll.java create mode 100644 Java/media/FText.java create mode 100644 Java/media/FirstMatchBreaker.java create mode 100644 Java/media/LineBreaker.java create mode 100644 Java/media/LineInfo.java create mode 100644 Java/media/README create mode 100644 Java/media/Scroll.java create mode 100644 Java/media/SimpleLineBreaker.java create mode 100644 Java/media/SimpleLineInfo.java create mode 100644 Java/media/SoundScroll.java create mode 100644 Java/media/Span.java create mode 100644 Java/media/SpanSet.java create mode 100644 Java/media/SpanTree.java create mode 100644 Java/media/Stream.java create mode 100644 Java/media/StringScroll.java create mode 100644 Java/media/TestLines.java create mode 100644 Java/media/UTF8Char.java create mode 100644 Java/media/VStream.java create mode 100644 Java/media/ZZDefaultText.java create mode 100644 Java/media/ZZHumber.java create mode 100644 Java/media/ZZSoundView.java create mode 100644 Java/media/ZZText.java create mode 100644 Java/mungencss.pl create mode 100644 Java/net/Peer.java create mode 100644 Java/net/ReliableUDPMessage.java create mode 100644 Java/net/ReliableUDPMessageFactory.java create mode 100644 Java/net/ReliableUDPSocket.java create mode 100644 Java/p2p/P2PStorage.java create mode 100644 Java/p2p/UniqueID.java create mode 100644 Java/part/BinaryTreePart.java create mode 100644 Java/part/DoubleStepPart.java create mode 100644 Java/part/GenTreePart.java create mode 100644 Java/part/GenTreePartModel.java create mode 100644 Java/part/GenTreeTestModel.java create mode 100644 Java/part/ImpliedTreePart.java create mode 100644 Java/part/ImpliedTreePart2.java create mode 100644 Java/part/VersionPart.java create mode 100644 Java/part/ZZROSpacePart.java create mode 100644 Java/part/ZZROStrSpacePart.java create mode 100644 Java/script/Makefile create mode 100644 Java/script/ZZId.h create mode 100644 Java/script/ZZScriptAPI_1_JNI.cpp create mode 100644 Java/script/ZZScriptAPI_1_JNI.h create mode 100644 Java/script/ZZScriptPerl.cpp create mode 100644 Java/script/ZZScriptPerl.java create mode 100644 Java/script/invoke.c create mode 100644 Java/storage/ContentStore.java create mode 100644 Java/storage/ContentStorer.java create mode 100644 Java/storage/CountingStream.java create mode 100644 Java/storage/DimStore.java create mode 100644 Java/storage/DirStreamSet.java create mode 100644 Java/storage/DummyStreamSet.java create mode 100644 Java/storage/FileWritable.java create mode 100644 Java/storage/Flushable.java create mode 100644 Java/storage/GZZ0.java create mode 100644 Java/storage/MemWritable.java create mode 100644 Java/storage/Recs.pl create mode 100644 Java/storage/SimpleContentFile.java create mode 100644 Java/storage/SimpleDimFile.java create mode 100644 Java/storage/Sliced.java create mode 100644 Java/storage/SlicedCursor.java create mode 100644 Java/storage/SlicedHomes.java create mode 100644 Java/storage/SlicedSame.java create mode 100644 Java/storage/StreamSet.java create mode 100644 Java/storage/Writable.java create mode 100644 Java/storage/ZZCacheContentStore.java create mode 100644 Java/storage/ZZCacheDimSpace.java create mode 100644 Java/storage/ZZCacheDimension.java create mode 100644 Java/storage/ZZDimStorer.java create mode 100644 Java/transform/ChangeDim.java create mode 100644 Java/transform/ClearDim.java create mode 100644 Java/transform/CopyDim.java create mode 100644 Java/transform/FoldDim.java create mode 100644 Java/transform/ReverseDim.java create mode 100644 Java/transform/Version0.java create mode 100644 Java/transform/Version1.java create mode 100644 Java/transform/Version2.java create mode 100644 Java/transform/VersionChanger.java create mode 100644 Java/zob2java.pl create mode 100644 LICENSE.lgpl create mode 100644 LICENSE.xpl create mode 100644 Makefile create mode 100644 Manifest create mode 100644 Modules/README create mode 100644 Modules/applet/ZZApplet.java create mode 100644 Modules/applet/example1.html create mode 100644 Modules/awtool/AwtCursor.java create mode 100644 Modules/awtool/AwtLink.java create mode 100644 Modules/awtool/AwtLink.zob create mode 100644 Modules/awtool/AwtMetrics.java create mode 100644 Modules/awtool/AwtMetrics.zob create mode 100644 Modules/awtool/AwtMetricsFC.java create mode 100644 Modules/awtool/AwtMetricsFC2.java create mode 100644 Modules/awtool/AwtMetricsNormal.java create mode 100644 Modules/awtool/AwtNileView.java create mode 100644 Modules/awtool/AwtNote.java create mode 100644 Modules/awtool/AwtNote.zob create mode 100644 Modules/awtool/AwtUtil.java create mode 100644 Modules/awtool/AwtView1.java create mode 100644 Modules/awtool/Awtool.java create mode 100644 Modules/awtool/Awtool.zob create mode 100644 Modules/awtool/BooleanMesh.java create mode 100644 Modules/awtool/README create mode 100644 Modules/awtool/TODO create mode 100644 Modules/awtool/ZObCellRepr.java create mode 100644 Modules/benchmark/GraphBench.java create mode 100644 Modules/benchmark/README create mode 100644 Modules/benchmark/ZZBench.java create mode 100644 Modules/benchmark/java2d/Java2DBench.java create mode 100644 Modules/database/DB0.java create mode 100644 Modules/database/createscript.pl create mode 100644 Modules/database/zz.queries create mode 100644 Modules/database/zz.sql create mode 100644 Modules/daytimedemo/Calendar2.zob create mode 100644 Modules/daytimedemo/ClockCellView.zob create mode 100644 Modules/daytimedemo/DayTimeDemo.zob create mode 100644 Modules/extern/Extern.java create mode 100644 Modules/hypergenealogy/HyperGenealogy.zob create mode 100644 Modules/iter/DimRecursor.java create mode 100644 Modules/iter/EnumVanishingView.zob create mode 100644 Modules/iter/Iter.java create mode 100644 Modules/iter/README create mode 100644 Modules/joystick/LinuxJoystick.java create mode 100644 Modules/mbox/SingleMail.zob create mode 100644 Modules/mbox/ZZDateParser.java create mode 100644 Modules/mbox/ZZMbox.java create mode 100644 Modules/mind/Mind.java create mode 100644 Modules/mind/MindSun.java create mode 100644 Modules/mind/MindSundew.java create mode 100644 Modules/multimedia/Default.java create mode 100644 Modules/multimedia/MediaFlobFactory.java create mode 100644 Modules/multimedia/MediaFlobView.java create mode 100644 Modules/multimedia/MediaMath.java create mode 100644 Modules/multimedia/MediaZOb.java create mode 100644 Modules/multimedia/Pixels.java create mode 100644 Modules/multimedia/PolygonRenderer.java create mode 100644 Modules/multimedia/Polygons.java create mode 100644 Modules/multimedia/adjust.java create mode 100644 Modules/multimedia/crop.java create mode 100644 Modules/multimedia/dots.java create mode 100644 Modules/multimedia/image.java create mode 100644 Modules/multimedia/mm.java create mode 100644 Modules/multimedia/move.java create mode 100644 Modules/multimedia/readme.html create mode 100644 Modules/multimedia/rect.java create mode 100644 Modules/multimedia/sin.java create mode 100644 Modules/nile/Nile1.java create mode 100644 Modules/nile/Nile1Div.java create mode 100644 Modules/nile/Nile1GenTreeModel.java create mode 100644 Modules/nile/Nile1Ops.java create mode 100644 Modules/nile/Nile1Text.java create mode 100644 Modules/nile/Nile1View.zob create mode 100644 Modules/nile/Nile2Iter.java create mode 100644 Modules/nile/Nile2Ops.java create mode 100644 Modules/nile/Nile2Test.java create mode 100644 Modules/nile/Nile2Unit.java create mode 100644 Modules/nile/NileApplet.java create mode 100644 Modules/nile/NileDemo.java create mode 100644 Modules/nile/README create mode 100644 Modules/nile/SplitNileDemo.java create mode 100644 Modules/nile/SplitNileView.zob create mode 100644 Modules/nile/draft/Nile3Ops.java create mode 100644 Modules/nile/draft/Nile3Part.java create mode 100644 Modules/nile/draft/Nile3Pos.java create mode 100644 Modules/nile/draft/Nile3Unit.java create mode 100644 Modules/notemap/Notemap.zob create mode 100644 Modules/openGL/Makefile create mode 100644 Modules/openGL/OpenGLCloud.java create mode 100644 Modules/openGL/ZZOpenGLGraphics.cc create mode 100644 Modules/openGL/ZZOpenGLGraphics.java create mode 100644 Modules/openGL/fi_iki_lukka_ZZOpenGLGraphics.h create mode 100644 Modules/panes/PaneView.zob create mode 100644 Modules/prez/Prez.java create mode 100644 Modules/prez/PrezRaster.zob create mode 100644 Modules/servlet/VCServlet.java create mode 100644 Modules/servlet/ZZServlet.java create mode 100644 Modules/servlet/startjetty create mode 100644 Modules/servlet/zzserv.prp create mode 100644 Modules/servlet/zzserv2.prp create mode 100644 Modules/sound/Player.java create mode 100644 Modules/sound/Recorder.java create mode 100644 Modules/sound/SimplePlayer.java create mode 100644 Modules/sound/SimpleRecorder.java create mode 100644 Modules/sound/Sound.java create mode 100644 Modules/sound/gsm_def.h create mode 100644 Modules/sound/gsm_player.c create mode 100644 Modules/sound/gsm_recorder.c create mode 100644 Modules/sound/org_gzigzag_module_SimplePlayer.h create mode 100644 Modules/sound/org_gzigzag_module_SimpleRecorder.h create mode 100644 Modules/test/README create mode 100644 Modules/test/TestClang1.java create mode 100644 Modules/test/TestHuge.java create mode 100644 Modules/test/TestUndo.java create mode 100644 Modules/textcloud/TextCloud.zob create mode 100644 Modules/virtualcommunity/MessageFlobFactory.zob create mode 100644 Modules/virtualcommunity/VCView1.java create mode 100644 Modules/virtualcommunity/VCView2.java create mode 100644 Modules/virtualcommunity/VCView3.java create mode 100644 Modules/virtualcommunity/VCView4.java create mode 100644 Modules/virtualcommunity/VirtualCommunity.zob create mode 100644 Modules/vob/Connection.java create mode 100644 Modules/vob/View.java create mode 100644 Modules/vob/Vob.java create mode 100644 Modules/vob/VobSet.java create mode 100644 Modules/vob/VobStore.java create mode 100644 Modules/wordnet/conv.pl create mode 100644 Modules/xml/XML.java create mode 100644 Modules/xml/old2xml.pl create mode 100644 Modules/zaubertrank/README.html create mode 100644 Modules/zaubertrank/TokenTextCellView.java create mode 100644 Modules/zaubertrank/ZaubertrankCellView.java create mode 100644 Modules/zaubertrank/old/Actions.java create mode 100644 Modules/zaubertrank/old/Evaluator.java create mode 100644 Modules/zaubertrank/old/ParsedView.zob create mode 100644 Modules/zaubertrank/old/Parser.java create mode 100644 Modules/zaubertrank/old/Primitive.java create mode 100644 Modules/zaubertrank/old/PrimitiveSet.java create mode 100644 Modules/zaubertrank/old/SimpleView.zob create mode 100644 Modules/zaubertrank/old/TokenFlob.java create mode 100644 Modules/zaubertrank/old/TokenGrouper.java create mode 100644 Modules/zaubertrank/old/Zaubertrank.java create mode 100644 Modules/zaubertrank/old/ZaubertrankPart.java create mode 100644 Modules/ztp/ZTPclient.java create mode 100644 Modules/ztp/ZTPserver.java create mode 100644 Modules/ztp/client/Action.java create mode 100644 Modules/ztp/client/Get.java create mode 100644 Modules/ztp/client/Put.java create mode 100644 Modules/ztp/client/RemotePieceData.zob create mode 100644 Modules/ztp/client/Response.java create mode 100644 Modules/ztp/client/Session.java create mode 100644 Modules/ztp/client/Subspace.java create mode 100644 Modules/ztp/common/LineBufferedIO.java create mode 100644 Modules/ztp/common/SubspaceDump.java create mode 100644 Modules/ztp/server/GetMessage.java create mode 100644 Modules/ztp/server/Listener.java create mode 100644 Modules/ztp/server/PutMessage.java create mode 100644 Modules/ztp/server/Session.java create mode 100644 Modules/ztp/server/UserManager.java create mode 100644 Modules/ztp/server/UserRecord.zob create mode 100644 NEWS create mode 100644 Perl/PerlServImpl.pm create mode 100644 Perl/README create mode 100644 Perl/ZZPerlDBServ.pm create mode 100644 Perl/ZZPerlServ.pm create mode 100644 Perl/ZZPerlSimpleClient.pm create mode 100644 Perl/cperl.pl create mode 100644 Perl/sperl.pl create mode 100644 README create mode 100644 VERSION create mode 100644 changelog-authors create mode 100644 cvsparser.pl create mode 100644 makedist.param create mode 100644 makedist.sh create mode 100644 manifest-filter.lst create mode 100644 manifest-filter.pl create mode 100644 md5sum diff --git a/C++/README b/C++/README new file mode 100644 index 0000000..c58acb0 --- /dev/null +++ b/C++/README @@ -0,0 +1,5 @@ +C++ version of gzizag +===================== +C++ version has been removed from here, because it's not usefull +anymore. + diff --git a/CODING b/CODING new file mode 100644 index 0000000..b9a76b9 --- /dev/null +++ b/CODING @@ -0,0 +1,122 @@ +Coding rules for GZigZag -*- Text -*- +======================== + Tuomas Lukka + Antti-Juhani Kaijanaho + +$Id: CODING,v 1.18 2001/03/08 15:05:12 tjl Exp $ + +This document attempts to give a brief guide on how to write +Java code for this project. + +- each Java file should contain the boilerplate copyright and + license notice (see e.g. Java/ZZCell.java). + +- all of the classes should be in a package. The packages are + org.gzigzag -- general core stuff + org.gzigzag.module -- modules + org.gzigzag.dimension -- dimensions for use with DimSpace + +- The main Java/ subdirectory may only depend on the JDK 1.1.8 APIs. + Swing is not allowed. + + There is also Java/exp for experimental things that touch the core + which may depend on anything but shall not be compiled by default. + + Modules/ can depend on anything, as long as the dependency is documented. + Nothing in the main Java/ subdirectory may depend on anything in Modules/ + This ensures that we retain portability and easy installation. All the user + has to do is to give up on a module that has an odd dependency, not the whole + system. + + Note that all modules need not be in the Modules/ subdirectory: for instance, + the TextCloud module does not depend on anything beyond the core Java code + and may in the future be called by the core Java code so it is located in + the core subdirectory. + + + +- Each class should start with the line (not indented to save space) + +public static final String rcsid = "$Id: CODING,v 1.18 2001/03/08 15:05:12 tjl Exp $"; + + except interfaces, which should have + +String rcsid = "$Id: CODING,v 1.18 2001/03/08 15:05:12 tjl Exp $"; + + instead. + + This will pull in the version identifier from the CVS file. + XXX IT SHOULD PROBABLY BE INCLUDED IN THE JAVADOC AS WELL! + +- For debugging log messages, use the code + + public static boolean dbg = false; + protected static void p(String s) { if(dbg) ZZLogger.log(s); } + protected static void pa(String s) { ZZLogger.log(s); } + + to print out messages. The System.out.println() is too verbose to insert + into code. This code can be added to the beginning of any class. + + NOTE THE CHANGE FROM PREVIOUS: there is NO "final" qualifier for dbg, + as a non-final dbg can be used on the commandline to switch debugging + on at runtime, without a recompilation. Not all files have been changed yet. + + NOTE THE CHANGE FROM PREVIOUS: We now use ZZLogger, allowing logging + the debug output into a file that can be sent to us in case of a + puzzling bug. This avoids having to have a scrollback buffer in + your terminal emulator. + + NOTE THE CHANGE FROM PREVIOUS: there are NO "final" qualifiers for p and pa, + because they are unnecessary for static methods. p and pa are now private. + Not all files have been changed yet. + + NOTE THE CHANGE FROM PREVIOUS: The methods are now protected; this allows + them to be used in subclasses. When they were private, debugging subclasses + was impossible. Not all files have been changed yet. + +- If you want to kill the program, use SafeExit.exit instead of System.exit; + this allows consistent cleanup at exit time + +- Avoid both under- and overdocumenting. + +- Use Java 1.1.8: use of 1.2 features is allowable IF you carefully check + that the code works in 1.1.8, minus the features given by 1.2. So for + instance, if you make a cache that works with the garbage collector + interface in 1.2 to enable passive cleaning, the code should run on 1.1.8, + either without the cache, or without the cleaning (currently the ZZCellScroll + caches without any cleaning). + + One of the considerations here is that Kaffe JVM provides a completely + free platform on which we can run the free GZigZag. If SUN or someone else + ever releases their Java implementation under a free license, the situation + is completely different. + +- Use anonymous classes freely + +- Try to keep the external APIs small, *with the exception* of providing + convenience routines for classes like ZZCell. + +- Indenting: tabstop==8, shiftwidth == 4, cuddled braces, i.e. + + public void method() { + if(...) { + ... + } else { + ... + } + } + + however, you may use smaller shiftwidth if the function really really requires + it (although you should try to split it up). + +- for any more complicated functionality, feel free to start a new + "white paper" -type documentation in the Documentation/ subdirectory. + +- make your code such that it can be compiled in jikes +P (pedantic), + JDK1.1.8 and JDK1.2.2 without warnings or errors. + +- as an aside, I really recommend using a coloring editor since there are + many points where significant sections have been commented out. This + is bad practice but inevitable in a system that doesn't easily allow + us to attach the sections which are not useful now but might be later + to the text in a xanadu-like manner. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..70add5d --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4403 @@ +2002-03-07 Thursday 21:02 Benjamin Fallenstein + + * Java/flob/: FlobSet.java, StdLinks.zob (ver_0_6): Fix FlobSet: + findPath(String path, ZZCell c) did not respect 'path'. + +2002-03-07 Thursday 19:56 Antti-Juhani Kaijanaho + + * NEWS, Documentation/index.html (ver_0_6): fix trivial doc bug, + see Debian BTS #128279 + +2002-03-07 Thursday 19:36 Benjamin Fallenstein + + * Java/ZZUtil.java (ver_0_6): Try fixing the depth bug that has + caused raster errors in prerelease. + +2002-03-07 Thursday 17:59 Benjamin Fallenstein + + * NEWS (ver_0_6): Update NEWS. + +2002-03-05 Tuesday 20:46 Benjamin Fallenstein + + * NEWS, Java/ZZUtil.java, Java/flob/RowColView.zob (ver_0_6): The + Row and Column views have been fixed to show the dimensions always. + Previously, in some common cases the dimensions were hidden under + the cells shown by the views. + +2002-03-05 Tuesday 19:48 Antti-Juhani Kaijanaho + + * NEWS (ver_0_6): preparation for 0.6.3 + +2002-03-05 Tuesday 18:21 Benjamin Fallenstein + + * Java/: ZZPrimitiveActions.java, ZZUtil.java (ver_0_6): Add a + version of PUICOPYLINE that makes each cell a paragraph + (PUICOPYRANK, invoked by Ctrl-Alt-C + +2002-02-16 Saturday 18:58 Tuukka Hastrup + + * Modules/prez/PrezRaster.zob (ver_0_6): Asko's Presenation view + fixes. BallCell went already in... + +2002-02-16 Saturday 18:56 Tuukka Hastrup + + * Java/Makefile (ver_0_6): Revert accidental Makefile change + +2002-02-16 Saturday 18:51 Tuukka Hastrup + + * Java/: Makefile, flob/BallCell.java (ver_0_6): Add Mind module to + JARMODULES too + +2002-02-16 Saturday 17:21 Antti-Juhani Kaijanaho + + * NEWS (ver_0_6): minor nits; ready for release? + +2002-02-16 Saturday 16:33 Tuukka Hastrup + + * Modules/mind/MindSun.java (ver_0_6): Really change to JDK 1.1 API + +2002-02-16 Saturday 16:25 Tuukka Hastrup + + * Modules/mind/MindSun.java (ver_0_6): Change to JDK 1.1 API + +2002-02-16 Saturday 15:46 Tuukka Hastrup + + * Modules/mind/Mind.java (ver_0_6): Added Asko's tree export + actions, (not in DefaultSpace yet) + +2002-02-16 Saturday 15:19 Tuukka Hastrup + + * Java/Makefile, Java/ZZDefaultSpace.java, Modules/mind/Mind.java, + Modules/mind/MindSun.java, Modules/mind/MindSundew.java (ver_0_6): + Added Asko's views as module Mind + +2002-02-16 Saturday 15:19 Tuukka Hastrup + + * Modules/mind/Mind.java: file Mind.java was initially added on + branch ver_0_6. + +2002-02-16 Saturday 15:19 Tuukka Hastrup + + * Modules/mind/MindSun.java: file MindSun.java was initially added + on branch ver_0_6. + +2002-02-16 Saturday 15:19 Tuukka Hastrup + + * Modules/mind/MindSundew.java: file MindSundew.java was initially + added on branch ver_0_6. + +2002-02-16 Saturday 14:19 Benjamin Fallenstein + + * NEWS (ver_0_6): Update NEWS again + +2002-02-16 Saturday 14:07 Benjamin Fallenstein + + * NEWS (ver_0_6): Update NEWS + +2002-02-13 Wednesday 13:48 Tuomas J. Lukka + + * Documentation/misc/argh-useful.jpeg: Why the argh-view can be + useful + +2002-02-10 Sunday 12:39 Benjamin Fallenstein + + * Java/ZZViewComponent.java (ver_0_6): Comment out consume() (the + offending call on JDK 1.2+) + +2002-02-10 Sunday 12:37 Benjamin Fallenstein + + * Java/ZZCursorReal.java (ver_0_6): Make compile (without modules, + at least) + +2002-02-08 Friday 07:57 Tuomas J. Lukka + + * Documentation/misc/gzz-functional-notes.sxw: Another day's work + towards functional cellviews + +2002-02-07 Thursday 09:25 Tuomas J. Lukka + + * Documentation/misc/: gzz-functional-notes.sxw, gzz-ogl-notes.sxw: + more + +2002-02-06 Wednesday 12:43 Tuomas J. Lukka + + * Documentation/misc/gzz-functional-notes.sxw: More stuff about + func prog + +2002-02-05 Tuesday 15:55 Tuomas J. Lukka + + * Documentation/misc/gzz-functional-notes.sxw: Ok, now... + +2002-02-05 Tuesday 12:55 Tuomas J. Lukka + + * Documentation/misc/gzz-functional-notes.sxw: Functional + +2002-02-04 Monday 14:57 Tuomas J. Lukka + + * Documentation/misc/PPPrototypeDesign.sxw: Important spec change + +2002-02-04 Monday 13:45 Tuomas J. Lukka + + * Documentation/misc/gzz-ogl-notes.sxw: Forgot to add this when + moving stuff + +2002-02-03 Sunday 19:29 Tuomas J. Lukka + + * Documentation/misc/gzz-ogl-notes.sxw: more + +2002-02-03 Sunday 11:18 Tuomas J. Lukka + + * Documentation/misc/gzz-ogl-notes.sxw: mor + +2002-02-02 Saturday 20:37 Tuomas J. Lukka + + * Documentation/misc/gzz-ogl-notes.sxw: More thoughts + +2002-02-02 Saturday 15:33 Tuomas J. Lukka + + * Documentation/misc/gzz-ogl-notes.sxw: Opengl notes + +2002-02-02 Saturday 12:36 Tuomas J. Lukka + + * Documentation/misc/: PPPrototypeDesign.sxw, + PPPrototypeDesign.sxw, PPPrototypeDesign.sxw: more + +2002-02-02 Saturday 11:10 Tuomas J. Lukka + + * Documentation/misc/: PPPrototypeDesign.sxw, + PPPrototypeDesign.sxw: more + +2002-02-02 Saturday 10:44 Tuomas J. Lukka + + * Documentation/misc/PPPrototypeDesign.sxw: more + +2002-02-02 Saturday 09:03 Tuomas J. Lukka + + * Documentation/misc/: PPPrototypeDesign.sxw, jyvasaly.txt: + Perheportaali design + +2002-01-17 Thursday 19:01 Benjamin Fallenstein + + * Documentation/Mediaserver/ms.wml: Add status information + throughout mediaserver doc, corrrect minor typos + +2002-01-16 Wednesday 19:48 Benjamin Fallenstein + + * Documentation/: Makefile, PROTOCOL, ApplitudeWriters/Makefile, + ApplitudeWriters/appw.wml, Networking/Makefile, + Networking/ZTP-usage.txt, Networking/ZTP.txt, + Networking/mock-ZTPTCP.txt, Networking/ztp.wml, misc/ADDRESSING, + misc/Curseling, misc/RENDERING, misc/TORESOLVE: Remove some + seemingly outdated documentation. Shout if something of this was + still important. + +2001-12-03 Monday 05:30 Antti-Juhani Kaijanaho + + * Documentation/misc/oske1.tex: update report dates + +2001-11-26 Monday 20:56 vegai + + * Documentation/misc/jyvasaly.txt: Few typos and obscurities + +2001-11-26 Monday 14:37 Tuomas J. Lukka + + * Documentation/misc/jyvasaly.txt: More + +2001-10-17 Wednesday 08:17 vegai + + * README: Documented 0.8-tree somewhat. (1st commit, be very + afraid) + +2001-10-11 Thursday 12:53 Tuomas J. Lukka + + * Documentation/misc/: nets-1.txt, nets-2.txt, nets-2.txt: more + +2001-10-11 Thursday 12:28 Tuomas J. Lukka + + * Documentation/misc/: nets-1.txt, nets-2.txt: more + +2001-10-11 Thursday 11:46 Tuomas J. Lukka + + * Documentation/misc/nets-1.txt: Changes + +2001-10-11 Thursday 11:20 Tuomas J. Lukka + + * Documentation/misc/nets-1.txt: Fmt, add COTS stuff + +2001-10-11 Thursday 11:17 Tuomas J. Lukka + + * Documentation/misc/: nets-1.txt, nets-2.txt: Add nets docs for + review + +2001-10-08 Monday 04:36 Tuomas J. Lukka + + * Documentation/: Mediaserver/ms.wml, Spec/zzspec.wml: Updates + +2001-10-03 Wednesday 11:21 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/gzigzag.bib: fix + +2001-10-02 Tuesday 05:30 Benjamin Fallenstein + + * Java/flob/RowColView.zob (ver_0_6): Fix RowCol's structparams and + add 'repeat' + +2001-09-21 Friday 08:14 Antti-Juhani Kaijanaho + + * Documentation/misc/oske1.tex: Correct HT01 reference + +2001-09-21 Friday 08:09 Antti-Juhani Kaijanaho + + * Documentation/misc/oske1.tex: Added explicit date range; noted + that 1stZZW talks were invited + +2001-09-17 Monday 10:21 Tuomas J. Lukka + + * Documentation/misc/oske1.tex: Typo + +2001-09-17 Monday 09:16 Tuomas J. Lukka + + * Documentation/misc/oske1.tex: OSKE first report, please read and + comment + +2001-08-29 Wednesday 08:32 Antti-Juhani Kaijanaho + + * Makefile: some stuff to make alpha releases + +2001-08-24 Friday 19:58 Benjamin Fallenstein + + * Java/flob/MagGrid.zob (ver_0_6): Make MagGrid default values so + much more useful + +2001-08-24 Friday 06:06 Antti-Juhani Kaijanaho + + * Java/ZZViewComponent.java (ver_0_6): revert focus change (if we + find a better fix, we can always do a 0.6.2) + +2001-08-17 Friday 12:15 Antti-Juhani Kaijanaho + + * manifest-filter.lst (ver_0_6): do not include src + +2001-08-17 Friday 12:13 Antti-Juhani Kaijanaho + + * NEWS (ver_0_6): prepare for the release + +2001-08-16 Thursday 14:51 Benjamin Fallenstein + + * Java/ZZDefaultSpace.java (ver_0_6): Add flowing clang execution + dimension to the standard dimension list + +2001-08-16 Thursday 14:51 Benjamin Fallenstein + + * Java/ZZKeyBindings1.java (ver_0_6): Ugly fix for Flowing Clang + execution as a key binding + +2001-08-16 Thursday 14:39 Benjamin Fallenstein + + * Java/ZZViewComponent.java (ver_0_6): Fix greedy focus + +2001-08-16 Thursday 14:19 Benjamin Fallenstein + + * NEWS (ver_0_6): Update NEWS + +2001-08-16 Thursday 14:13 Benjamin Fallenstein + + * Java/ZZPrimitiveActions.java (ver_0_6): Oopsie, forgot to add + EDITHACK to actions list + +2001-08-16 Thursday 14:09 Benjamin Fallenstein + + * Java/ZZPrimitiveActions.java (ver_0_6): Make flowing clang + programs work directly as actions (i.e., now one can write a + flowing clang function and clone it directly onto the key bindings + list). Now, testing; then, from my side we're ready for the next + 0.6 release. + +2001-08-16 Thursday 13:50 Benjamin Fallenstein + + * Java/: ZZTextView.java, media/LineBreaker.java (ver_0_6): Set + window bounds for text view; fix compilation with Klasses.jar + +2001-08-16 Thursday 13:40 Benjamin Fallenstein + + * Java/: Makefile, clang/flowing/Flowing.java (ver_0_6): Make + Flowing Clang compile again + +2001-08-16 Thursday 08:48 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml, Java/Makefile, + Java/clang/flowing/Flowing.java: Make flowing clang work again, + update spec, Add println clasm primitive and twiddle with linux + joystick + +2001-08-12 Sunday 09:00 Antti-Juhani Kaijanaho + + * Makefile: update ChangeLog + +2001-08-11 Saturday 16:29 Tuukka Hastrup + + * Documentation/: Clang_Design/.cvsignore, Mediaserver/.cvsignore, + Spec/.cvsignore: Ignore more autogenerated files + +2001-08-08 Wednesday 14:55 Tuukka Hastrup + + * Documentation/Clang_Design/clasm.wml: Update dimension names in + the text + +2001-08-08 Wednesday 14:46 Tuukka Hastrup + + * Documentation/Clang_Design/clasm-tutorial.wml: Update dimension + names in the text (not in pictures) + +2001-08-06 Monday 15:28 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: fix + +2001-08-06 Monday 15:17 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: Span storage stuff + +2001-08-05 Sunday 15:04 Tuomas J. Lukka + + * Documentation/: Makefile, Mediaserver/ms.wml: Saving + +2001-08-05 Sunday 14:08 Tuomas J. Lukka + + * Documentation/Mediaserver/ms.wml: Pointers proposal + +2001-08-05 Sunday 10:58 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Make the syntax parse a little + better + +2001-08-05 Sunday 10:55 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: fix + +2001-08-05 Sunday 10:47 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Upd format + +2001-08-05 Sunday 10:24 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Edit + +2001-08-01 Wednesday 18:40 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Start working on mediaserver + scrollblocks + +2001-08-01 Wednesday 14:55 Rauli Ruohonen + + * Documentation/Spec/mainloop.jpg: Pic of main loop + +2001-07-30 Monday 10:01 Antti-Juhani Kaijanaho + + * Makefile, manifest-filter.lst: release builds src/ jars now and + ignores Java/ + +2001-07-25 Wednesday 11:01 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/ms.wml: Make the HTTP interface spec + match current expectations. + +2001-07-25 Wednesday 10:45 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/ms.wml: committing something i've + forgotten to commit previously + +2001-07-21 Saturday 21:00 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: Start thinking about file format + representation for the new spans + +2001-07-21 Saturday 20:37 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: some more + +2001-07-21 Saturday 18:16 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: A bit more + +2001-07-21 Saturday 18:06 Benjamin Fallenstein + + * Documentation/Spec/: span-insertion-after.gif, + span-insertion-before.gif: add + +2001-07-21 Saturday 18:04 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: doc fixes + +2001-07-21 Saturday 13:18 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: Some doccing about the new span + concepts + +2001-07-19 Thursday 18:22 Benjamin Fallenstein + + * Documentation/Clang_Design/: 1.gif, 2.gif, 3.gif, 4.gif, 5.gif, + 6.gif, 7.gif, clasmpics.html: clasm pics (as on the mailing list, + plus comments-- don't count on them making too much sense ;) ;)) + +2001-07-19 Thursday 17:41 Rauli Ruohonen + + * Documentation/Mediaserver/ms.wml: Pics to the wml. + +2001-07-19 Thursday 17:27 Tuomas J. Lukka + + * Documentation/Makefile: Oooppsss - have forgotten to add these + +2001-07-19 Thursday 17:26 Rauli Ruohonen + + * Documentation/Mediaserver/ms.wml: Added obsoleteness comment to + 'a scheme'. + +2001-07-19 Thursday 16:47 Tuomas J. Lukka + + * Documentation/: DesignProblems/ABCD.jpg, + DesignProblems/ConflictLevels.jpg, + DesignProblems/DifficultMerge.jpg, + DesignProblems/LLMergeProblem.jpg, + DesignProblems/LLMergeProblem2.jpg, + DesignProblems/LargeScaleRearrange.jpg, DesignProblems/Makefile, + DesignProblems/RelationConflict.jpg, DesignProblems/SegCases.jpg, + DesignProblems/SegExamples.jpg, DesignProblems/dp.wml, + DesignProblems/mergemath.tex, diagrams/Molecule1.jpg, + diagrams/Molecule2.jpg, diagrams/Molecule3.jpg: Reorganize + Designproblems by splitting off merging + +2001-07-17 Tuesday 13:49 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: update spec: no inclusions, but + transcopies in file format + +2001-07-16 Monday 21:37 Tuomas J. Lukka + + * Documentation/: Spec/sliceinclusion-dimsame.jpg, Spec/zzspec.wml, + wmlinc/art.css: Make images take less space horizontally + +2001-07-16 Monday 16:11 Rauli Ruohonen + + * Documentation/Spec/: spaces1.jpeg, spaces2.jpeg, spaces3.jpeg, + zzspec.wml: Some inclusion pics + +2001-07-12 Thursday 14:58 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: Move inclusion parts after ID of + previous spaces + +2001-07-11 Wednesday 11:31 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: I take the content section spec + back: new cells should be independent of delete cells, because the + first ought to be at the beginning and the second ought to be at + the end of the delta. + +2001-07-11 Wednesday 10:43 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: Change file format ebnf to have + cell status sections like in GZZ1Handler + +2001-07-09 Monday 18:39 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: Removed my proposal. It was no + longer relevant. + +2001-07-09 Monday 18:08 Tuukka Hastrup + + * Documentation/wmlinc/: art.css, common.wml: Reply to Tuomas + +2001-07-09 Monday 13:30 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Move inclusion parts + +2001-07-09 Monday 13:27 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Fix + +2001-07-09 Monday 13:21 Tuomas J. Lukka + + * Documentation/Makefile: Add to makefile, comment + +2001-07-09 Monday 12:27 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Comment + +2001-07-09 Monday 11:20 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: Comment on library call dispatch. + +2001-07-09 Monday 11:04 Tuomas J. Lukka + + * Documentation/Spec/: zzspec.wml, zzspec.wml: Note about dimension + ids + +2001-07-09 Monday 10:59 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: More id stuff + +2001-07-09 Monday 10:48 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: Put my proposal to the perspective + it was intended to be in. + +2001-07-09 Monday 10:39 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Format for inclusion + +2001-07-08 Sunday 19:30 Tuomas J. Lukka + + * Documentation/Spec/: sliceinclusion-containment.jpg, + sliceinclusion-simple.jpg, zzspec.wml: Some more + +2001-07-08 Sunday 18:14 Tuomas J. Lukka + + * Documentation/Spec/: sliceinclusion-containment.jpg, + sliceinclusion-dimsame.jpg, sliceinclusion-preflet-types.jpg, + sliceinclusion-simple.jpg, sliceinclusion-upgrade-conflict.jpg, + sliceinclusion-upgrade.jpg, zzspec.wml: More stuff about inclusions + +2001-07-07 Saturday 19:36 Tuomas J. Lukka + + * Documentation/Makefile: Make the makefile make something by + default. Distdocs is what one'd usually want. + +2001-07-07 Saturday 16:44 Tuomas J. Lukka + + * Documentation/Spec/transspace-versioning-inclusion.jpg: Fix image + +2001-07-07 Saturday 16:36 Tuomas J. Lukka + + * Documentation/Spec/: transspace-versioning-inclusion.jpg, + transspace-versioning.jpg, zzspec.wml: More comments + +2001-07-07 Saturday 15:22 Tuomas J. Lukka + + * Documentation/: Clang_Design/Makefile, Spec/zzspec.wml: Comments + +2001-07-07 Saturday 13:48 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: Oops + +2001-07-07 Saturday 13:45 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: Clarifying the cell id stuff. + +2001-07-07 Saturday 12:55 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: More cell id stuff. + +2001-07-07 Saturday 12:18 Rauli Ruohonen + + * Documentation/Spec/zzspec.wml: Adding cell identity stuff to + zzspec, as requested by tjl. + +2001-07-07 Saturday 10:05 Tuomas J. Lukka + + * Documentation/Makefile: Make makefile make + +2001-07-06 Friday 11:34 Benjamin Fallenstein + + * Documentation/Spec/zzspec.wml: Notes about transcopies in the + file format + +2001-07-06 Friday 00:37 Benjamin Fallenstein + + * Documentation/misc/cellids: stuff about cell ids and related + issues + +2001-07-04 Wednesday 12:38 uid31808 + + * Documentation/Clang_Design/clasm-tutorial.wml: Add some notes to + the pictures + +2001-07-04 Wednesday 11:00 uid31808 + + * Documentation/Clang_Design/clasm-1.gif: correct + +2001-07-04 Wednesday 08:54 uid31808 + + * Documentation/Clang_Design/: clasm-1.gif, clasm-2.gif, + clasm-3.gif, clasm-4.gif, clasm-5.gif: Some images + +2001-07-03 Tuesday 13:51 Benjamin Fallenstein + + * Documentation/Clang_Design/clasm.wml: More work on the clasm + definition + +2001-07-02 Monday 11:20 Benjamin Fallenstein + + * Documentation/Clang_Design/clasm.wml: Clasm design (not finished, + and actually not converted to WML yet) + +2001-07-02 Monday 04:08 Tuomas J. Lukka + + * CODING: Mention collections + +2001-07-01 Sunday 19:08 Benjamin Fallenstein + + * Java/UndoList.java: Fix what I'm pretty sure is a bug + +2001-07-01 Sunday 17:23 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Fix span spec + +2001-07-01 Sunday 16:08 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Fix lookahead bug + +2001-07-01 Sunday 15:29 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Benja: should specify prev space + +2001-07-01 Sunday 15:26 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Benja's request: 0 -> 00 in end + +2001-07-01 Sunday 15:24 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: Finish? the format + +2001-07-01 Sunday 14:26 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: More syntax + +2001-07-01 Sunday 13:06 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: More format, version comment + +2001-07-01 Sunday 12:53 Tuomas J. Lukka + + * Documentation/Spec/: SCRATCH, zzspec.wml, zzspec.wml: Start + working towards new file format. Move stuff that doesn't belong + into the spec into the scratch document. Point out to Tuukka where + he should start. + +2001-06-29 Friday 20:09 Rauli Ruohonen + + * Documentation/Math/math.ptex: Added raster definition + +2001-06-29 Friday 14:47 Tuomas J. Lukka + + * Documentation/Mediaserver/: id-format.jpg, id-sig-scheme.jpg: Add + images + +2001-06-29 Friday 14:15 Tuomas J. Lukka + + * Documentation/diagrams/revper-3.jpg: Third revper diagram + +2001-06-29 Friday 10:57 Tuomas J. Lukka + + * Documentation/diagrams/revper-2.jpg: A second diagram about + revper + +2001-06-29 Friday 10:51 Tuomas J. Lukka + + * Documentation/diagrams/revper-1.jpg: New diagram about reverse + perspective + +2001-06-29 Friday 08:45 Benjamin Fallenstein + + * Documentation/Mediaserver/ms.wml: Few comments + +2001-06-28 Thursday 23:12 Tuomas J. Lukka + + * Documentation/Mediaserver/ms.wml: A little more discussion + +2001-06-28 Thursday 22:38 Benjamin Fallenstein + + * Documentation/Mediaserver/ms.wml: Umlauts into HTML entities + +2001-06-28 Thursday 22:36 Benjamin Fallenstein + + * Documentation/Mediaserver/ms.wml: Update somewhat after IRC + discussion + +2001-06-28 Thursday 18:34 Tuomas J. Lukka + + * Documentation/Mediaserver/spoof-3rdparty.jpg: Add spoof image + +2001-06-21 Thursday 12:49 Tuomas J. Lukka + + * Documentation/Clang_Design/preflet_ladder.jpg: An amusing ladder + +2001-06-21 Thursday 11:17 Tuomas J. Lukka + + * Documentation/Clang_Design/cursor-impliedcells.jpg: Image + +2001-06-21 Thursday 11:03 Rauli Ruohonen + + * Documentation/Clang_Design/spacepart-cursor.jpeg: Doesn't work. + +2001-06-21 Thursday 10:22 Rauli Ruohonen + + * Documentation/Clang_Design/spacepart-cursor.jpeg: [no log + message] + +2001-06-21 Thursday 09:27 Tuomas J. Lukka + + * Documentation/: CyberText/1.png, CyberText/3.png, + CyberText/4.png, CyberText/Makefile, CyberText/ct-old.wml, + CyberText/ct.wml, CyberText/email.dia, CyberText/kello-o.png, + CyberText/kello.png, CyberText/permascroll.dia, + CyberText/rank1vert.dia, CyberText/rank2vert.dia, + CyberText/rank3both.dia, CyberText/vilma.png, Syntaxless/synt.wml: + Move manuscripts + +2001-06-21 Thursday 09:18 Tuomas J. Lukka + + * Documentation/: CellScroll/SCRATCH, DimBased/Makefile, + DimBased/dim.ptex, Interfacing/.cvsignore, Interfacing/Makefile, + Interfacing/int.ptex: Remove obsolete stuff + +2001-06-18 Monday 11:49 Kimmo Wideroos + + * Java/ZZGroupHighlightCache.java: get -method + +2001-06-18 Monday 04:54 Kimmo Wideroos + + * Java/flob/MultiFocusView.zob: minor + +2001-06-16 Saturday 09:53 Tuomas J. Lukka + + * Documentation/DesignProblems/mergemath.tex, Java/Makefile: Some + som code independent of everything else. For use in cookbook view + and possibly others. + +2001-06-14 Thursday 21:41 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Make use of collections API + (which is included in debian's Kaffe) in Merge1. Makes code much + more readable, also almost working molecules + +2001-06-13 Wednesday 21:42 Tuomas J. Lukka + + * Modules/joystick/LinuxJoystick.java: Make filename used for test + changeable. + +2001-06-13 Wednesday 21:42 Tuomas J. Lukka + + * Documentation/index.html: Fix index + +2001-06-13 Wednesday 21:37 Tuomas J. Lukka + + * Documentation/: DesignProblems/dp.wml, + DesignProblems/mergemath.tex, diagrams/Molecule1.jpg, + diagrams/Molecule2.jpg, diagrams/Molecule3.jpg: More work on dp + +2001-06-13 Wednesday 11:29 Kimmo Wideroos + + * Java/: ZZGroupHighlightCache.java, ApplitudeMgr.java, + ZZDefaultSpace.java, ZZPrimitiveActions.java, flob/ClockView.zob, + flob/MultiFocusView.zob: multifocusview - several applitudes on + same view so that the layout changes as the focus changes. + +2001-06-12 Tuesday 00:01 Tuomas J. Lukka + + * Documentation/: DesignProblems/Makefile, DesignProblems/dp.wml, + DesignProblems/mergemath.tex, diagrams/Molecule1.jpg, + diagrams/Molecule2.jpg, diagrams/Molecule3.jpg, wmlinc/art.css: + More mergemath + +2001-06-09 Saturday 09:45 Kimmo Wideroos + + * Java/flob/CellFlobFactory1.zob: ...oops! forgot + +2001-06-09 Saturday 09:41 Kimmo Wideroos + + * Java/: ZZCanvasView.java, ZZGroupHighlightCache.java, + ZZKeyBindings1.java, ZZPrimitiveActions.java: (experimental...) + highlight cell(s) mouse touches + +2001-06-09 Saturday 09:27 Kimmo Wideroos + + * Java/ZZDefaultSpace.java: ClockView added in views + +2001-06-09 Saturday 09:26 Kimmo Wideroos + + * Java/flob/ClockView.zob: flobs arranged around a circle / 1-d + view + +2001-06-09 Saturday 09:24 Kimmo Wideroos + + * Java/ZZUtil.java: small fix: showDims support 1-d view + +2001-06-07 Thursday 09:55 Tuomas J. Lukka + + * Documentation/DesignProblems/: Makefile, dp.wml, mergemath.tex: + Integrate mergemath into dp + +2001-06-05 Tuesday 21:28 Benjamin Fallenstein + + * Documentation/Mediaserver/ms.wml: Gah, I've misread something. + Removed comment + +2001-06-05 Tuesday 18:52 Tuomas J. Lukka + + * Documentation/: DesignProblems/Makefile, DesignProblems/dp.wml, + DesignProblems/mergemath.tex, Mediaserver/Makefile, + Mediaserver/ms.wml, wmlinc/article.wml: More stuff. Merge logic. + Mediaserver crypto + +2001-06-02 Saturday 21:16 Antti-Juhani Kaijanaho + + * Documentation/wmlinc/: art.css, common.wml: ibid's voice + +2001-06-01 Friday 19:25 Benjamin Fallenstein + + * Documentation/Mediaserver/ms.wml: Update, commment + +2001-05-31 Thursday 06:46 Kimmo Wideroos + + * Documentation/misc/byrokratiadoku.txt: text-version, personnel + section slightly revisioned. + +2001-05-30 Wednesday 10:13 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Note about independence + +2001-05-30 Wednesday 10:10 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Define terminology for + change chunks: quarks, atoms, molecules + +2001-05-29 Tuesday 13:21 Tuomas J. Lukka + + * Documentation/Mediaserver/ms.wml: Ids + +2001-05-29 Tuesday 13:03 Tuomas J. Lukka + + * Documentation/Mediaserver/ms.wml: Remove the vulnerable scheme + +2001-05-29 Tuesday 12:52 Tuomas J. Lukka + + * Documentation/: DesignProblems/dp.wml, Mediaserver/ms.wml, + wmlinc/article.wml: Make ms doc validate correctly with w3c + validator. + +2001-05-29 Tuesday 12:29 Tuomas J. Lukka + + * Documentation/wmlinc/: art.css, common.wml: Colors + +2001-05-29 Tuesday 11:15 Tuomas J. Lukka + + * Documentation/Mediaserver/: ms.wml, ms.wml, ms.wml: More + +2001-05-29 Tuesday 10:43 Tuomas J. Lukka + + * Documentation/Mediaserver/: mediaserver.tex, ms.wml: Convert to + WML-HTML + +2001-05-28 Monday 07:28 Benjamin Fallenstein + + * Documentation/DesignProblems/dp.wml: Refer to Semantics + +2001-05-26 Saturday 17:24 Tuomas J. Lukka + + * Documentation/: DesignProblems/dp.wml, wmlinc/art.css: Merge + stuff. Talk and code. + +2001-05-25 Friday 12:54 Benjamin Fallenstein + + * Documentation/: DesignProblems/dp.wml, wmlinc/art.css, + wmlinc/common.wml: comment + +2001-05-24 Thursday 20:40 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Comment about "n" + dimensions. + +2001-05-24 Thursday 20:30 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Added stuff about 1:1 + dimensions to merge. + +2001-05-24 Thursday 19:11 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Clarifications. + +2001-05-24 Thursday 18:30 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Minor fix to the split rank + algorithm + a comment. + +2001-05-24 Thursday 18:19 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Change chunks + +2001-05-24 Thursday 18:07 Tuomas J. Lukka + + * Documentation/: DesignProblems/CornerListViolation.jpg, + DesignProblems/dp.wml, Gentle_Introduction/gi.wml, + diagrams/CornerListViolation.jpg: Move discussion of structural + design + +2001-05-24 Thursday 17:32 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Some more comments + +2001-05-24 Thursday 14:15 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Clarified myself wrt. + multiple split ranks. + +2001-05-23 Wednesday 21:10 Antti-Juhani Kaijanaho + + * Documentation/Spec/: formal.tex, oz.sty: a WIP spec in Z + +2001-05-23 Wednesday 20:23 Antti-Juhani Kaijanaho + + * Documentation/DesignProblems/dp.wml: fix a wml syntax error + +2001-05-23 Wednesday 19:43 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Committing, as I'm going + home now. I don't know whether I make any sense, as I don't have + time now to read what I wrote.. Anyway, added stuff about merging + split ranks. + +2001-05-23 Wednesday 16:38 Tuomas J. Lukka + + * Documentation/Manuscripts/gzigzag.bib: More refs + +2001-05-23 Wednesday 16:27 Rauli Ruohonen + + * Documentation/: DesignProblems/dp.wml, wmlinc/art.css, + wmlinc/common.wml: Added stuff about merging to dp. + +2001-05-23 Wednesday 14:56 Tuomas J. Lukka + + * Documentation/: Glossary/gl.wml, Manuscripts/gzigzag.bib: new + versioning refs. Mostly available through citeseer. + +2001-05-23 Wednesday 13:29 Tuomas J. Lukka + + * Documentation/Gentle_Introduction/: Cells.jpg, Dims.jpg, + ListGridTreeMesh.jpg, LocalGlobal.jpg, SpreadSheet.jpg, gi.wml: + Pictures + +2001-05-23 Wednesday 12:22 Tuomas J. Lukka + + * Documentation/DesignProblems/: ConflictLevels.jpg, dp.wml, + dp.wml: Conflict levels + +2001-05-23 Wednesday 10:08 Rauli Ruohonen + + * Documentation/: DesignProblems/dp.wml, RauliLogo.png: [no log + message] + +2001-05-23 Wednesday 05:43 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Some ancient uncommitted + changes. + +2001-05-22 Tuesday 11:24 Tuomas J. Lukka + + * Documentation/DesignProblems/: RelationConflict.jpg, dp.wml: Ok, + getting there. Biggest problem seems now to be HTML and the page + layout. Urgh. Hope we can get ZZ there soon + +2001-05-21 Monday 09:45 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: The floating images seem to + be impossible for anything else except mozilla to handle. Sad. + +2001-05-21 Monday 08:02 Tuomas J. Lukka + + * Documentation/: DesignProblems/ABCD.jpg, + DesignProblems/LLMergeProblem.jpg, + DesignProblems/LLMergeProblem2.jpg, DesignProblems/SegCases.jpg, + DesignProblems/SegExamples.jpg, DesignProblems/beamorder.png, + DesignProblems/dp.wml, DesignProblems/linkorder.png, + wmlinc/art.css: Some images, getting towards solution + +2001-05-20 Sunday 08:01 Tuomas J. Lukka + + * Documentation/wmlinc/art.css: Adjust margin + +2001-05-19 Saturday 18:10 Tuomas J. Lukka + + * Documentation/TjlLogo.png: Add + +2001-05-19 Saturday 18:06 Tuomas J. Lukka + + * Documentation/: DesignProblems/dp.wml, wmlinc/art.css, + wmlinc/common.wml: Add voices to the DesignProblems doc. We should + discuss this kind of thing in more detail at some point, as it + seems that all our docs are going that way - is it just me or is it + actully useful? It seems to work so that there is one editor, who + decides what the 'absolute' voice is and he and others as well + discuss things and propose changes. Also, if you feel like it, you + can make a logo and pick a color for yourself - it clarifies the + comments somewhat. + +2001-05-18 Friday 23:06 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Mods. + +2001-05-18 Friday 19:32 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Corrected myself. + +2001-05-18 Friday 17:44 Rauli Ruohonen + + * Documentation/DesignProblems/dp.wml: Added basic stuff about + identity cells. + +2001-05-18 Friday 12:08 Tuomas J. Lukka + + * Documentation/: DesignProblems/dp.wml, wmlinc/art.css: More stuff + about versioning. Please read, some important ideas inside (see + Linked-list approach fails) + +2001-05-17 Thursday 21:02 Tuomas J. Lukka + + * Documentation/DesignProblems/: CornerListViolation.jpg, + DifficultMerge.jpg, LargeScaleRearrange.jpg, dp.wml: Add images + +2001-05-17 Thursday 09:18 Tuomas J. Lukka + + * Documentation/: lib.mk, DesignProblems/dp.wml, wmlinc/art.css: + More design + +2001-05-16 Wednesday 14:33 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: More + +2001-05-16 Wednesday 13:54 Tuomas J. Lukka + + * Documentation/: DesignProblems/dp.wml, wmlinc/art.css: Remove + out-of-date stuff. Add styles for speakers. + +2001-05-16 Wednesday 08:42 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Start reviving this + document. Please put in comments etc. + +2001-05-15 Tuesday 14:26 Kimmo Wideroos + + * Documentation/Manuscripts/Awt/view-zzstructure.epsi: awt + iew+struct for dummies + +2001-05-15 Tuesday 14:23 Kimmo Wideroos + + * Documentation/Manuscripts/Awt/awt.tex: awt (work in progress) + description + +2001-05-15 Tuesday 14:18 Kimmo Wideroos + + * Documentation/Manuscripts/gzigzag.bib: awt refs + +2001-05-15 Tuesday 04:33 Tuomas J. Lukka + + * Documentation/Manuscripts/gzigzag.bib: Work on image scrolls + +2001-05-11 Friday 17:38 Vesa Parkkinen + + * Documentation/Manuscripts/gzigzag.bib: added robertson91 + +2001-05-11 Friday 14:33 Kimmo Wideroos + + * Documentation/Manuscripts/gzigzag.bib: Berlage's taps ref + +2001-05-11 Friday 07:07 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: Makefile, hyps.tex: oho + +2001-05-10 Thursday 21:32 Rauli Ruohonen + + * Java/flob/: RankTextView.zob, SplitCellFlob1.java: The real fix + by Tuomas. + +2001-05-10 Thursday 20:57 Rauli Ruohonen + + * Java/flob/RankTextView.zob: A terrible, non-working hack. + +2001-05-10 Thursday 13:47 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyps.tex: more... + +2001-05-10 Thursday 13:36 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyps.tex: Some more + +2001-05-10 Thursday 10:17 Tuomas J. Lukka + + * Java/flob/SimpleBeamer.zob: More baming + +2001-05-10 Thursday 09:57 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyps.tex: bah + +2001-05-10 Thursday 09:55 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyps.tex: Some more + +2001-05-10 Thursday 08:33 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyps.tex: A rather trivial + shortening of hyp, focusing on RFCs as a document set + +2001-05-09 Wednesday 16:01 Benjamin Fallenstein + + * Java/ZZTextView.java (ver_0_6): Update + +2001-05-09 Wednesday 15:41 Benjamin Fallenstein + + * Java/: ZZPrimitiveActions.java, ZZTextView.java (ver_0_6): A + quick hack for Marlene using AWT for editing + +2001-05-09 Wednesday 12:33 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/gzigzag.bib: Fix GZZ capitalization + +2001-05-09 Wednesday 10:21 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/gzigzag.bib: some references + +2001-05-06 Sunday 22:27 Tuomas J. Lukka + + * Documentation/Manuscripts/gzigzag.bib: Add jazz ref + +2001-04-30 Monday 09:31 Tuomas J. Lukka + + * Java/: arch/java2d/ZZDrawingJ2D.java, flob/SceneFlob.java: Fix my + quick fix that reverted Benja's work. Now RotatedSceneFlob + correctly says that it doesn't need a box + +2001-04-30 Monday 08:38 Tuomas J. Lukka + + * Java/flob/FTextLayouter.zob, + Modules/virtualcommunity/MessageFlobFactory.zob: More + virtualcommunity fixes + +2001-04-30 Monday 08:23 Tuomas J. Lukka + + * Java/flob/SceneFlob.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Make + virtualcommunity demo work again: SceneFlob MUST NOT BE BOXED FLOB: + rotated sceneflobs go totally screwy. + +2001-04-29 Sunday 22:21 Tuomas J. Lukka + + * Documentation/Manuscripts/gzigzag.bib: Ref + +2001-04-25 Wednesday 09:36 Tuomas J. Lukka + + * Modules/benchmark/GraphBench.java: Color benchmark + +2001-04-24 Tuesday 11:13 Tuomas J. Lukka + + * Documentation/Manuscripts/: gzigzag.bib, gzigzag.bib: More + +2001-04-24 Tuesday 07:36 Tuomas J. Lukka + + * Documentation/Manuscripts/gzigzag.bib: Ref + +2001-04-23 Monday 21:56 Benjamin Fallenstein + + * Modules/zaubertrank/Zaubertrank.java: Simplify a LOT + +2001-04-23 Monday 21:45 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankTemplate.java: Simplify + +2001-04-23 Monday 21:22 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankCellView.java: Some work on the + zaubertrank + +2001-04-23 Monday 14:19 Benjamin Fallenstein + + * Modules/zaubertrank/Zaubertrank.java: Make it (somewhat) work + +2001-04-23 Monday 13:25 Benjamin Fallenstein + + * Modules/zaubertrank/Zaubertrank.java: yet more + +2001-04-23 Monday 13:18 Benjamin Fallenstein + + * Modules/zaubertrank/: Zaubertrank.java, ZaubertrankTemplate.java: + More internals of the zaubertrank + +2001-04-23 Monday 12:12 Benjamin Fallenstein + + * Java/VirtualEditCursor.java: add size() to VirtualEditCursor + +2001-04-23 Monday 12:07 Benjamin Fallenstein + + * Java/VirtualEditCursor.java: Make VirtualEditCursor impl more + reasonable + +2001-04-23 Monday 11:38 Benjamin Fallenstein + + * Java/: EditCursor.java, VirtualEditCursor.java: Virtual edit + cursors + +2001-04-21 Saturday 16:34 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankTemplate.java: more + +2001-04-21 Saturday 12:39 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankTemplate.java: Hah! Another + successful iteration of the zaubertrank! ;) + +2001-04-21 Saturday 04:31 Benjamin Fallenstein + + * Java/Makefile, Modules/zaubertrank/ZaubertrankTemplate.java: + Small addition to the test + +2001-04-21 Saturday 04:24 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankTemplate.java: Yet another small + zaubertrank iteration (this is working towards a better editor, but + building abstractions in small steps first, to be sure they work + right) + +2001-04-21 Saturday 03:51 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankTemplate.java: Yet more work on + the zaubertrank + +2001-04-21 Saturday 01:11 Benjamin Fallenstein + + * Java/p2p/P2PStorageCache.java: Make p2p compile by creating dummy + method bodies in P2PStorageCache + +2001-04-21 Saturday 01:04 Benjamin Fallenstein + + * Java/Makefile: Make tests compiled and run by default, like in + the new API (archieved by defaulting ARCH to junit). + +2001-04-21 Saturday 01:02 Benjamin Fallenstein + + * Java/: media/ImageSpan.java, transform/Version2.java: Make + compile without warnings (except for p2p) + +2001-04-19 Thursday 18:33 Benjamin Fallenstein + + * Java/Makefile: Make compile again + +2001-04-19 Thursday 14:49 Benjamin Fallenstein + + * Modules/zaubertrank/Zaubertrank.java: Small changes + +2001-04-19 Thursday 05:59 Benjamin Fallenstein + + * Java/ZZUtil.java, Modules/zaubertrank/Zaubertrank.java, + Modules/zaubertrank/ZaubertrankCellView.java: More work on the + zaubertrank, make keyboard editing work as well as mouse editing + (however, both are somewhat crude still) + +2001-04-18 Wednesday 23:38 Benjamin Fallenstein + + * Java/ZZCell.java: Make old intersect() and intersectAll() + implementations include the cells they're starting at; they're part + of the rank, so they can form an intersection (i.e. if one of the + two start cells is on the rank the other start cell forms) + +2001-04-18 Wednesday 21:46 Benjamin Fallenstein + + * Java/flob/.cvsignore: Add SimpleBeamer2 + +2001-04-18 Wednesday 21:46 Benjamin Fallenstein + + * Java/Makefile: Add Archimedes to makefile + +2001-04-18 Wednesday 21:40 Benjamin Fallenstein + + * Java/EditCursor.java, Java/ZZDefaultSpace.java, + Java/ZZModule.java, Java/ZZPrimitiveActions.java, + Modules/zaubertrank/Zaubertrank.java, + Modules/zaubertrank/ZaubertrankCellView.java: More fiddling with + the zaubertrank; make actions taking dirs work in modules + +2001-04-18 Wednesday 19:22 Tuomas J. Lukka + + * Java/EditCursor.java: Fix unclosed em + +2001-04-17 Tuesday 16:40 Antti-Juhani Kaijanaho + + * Java/: Makefile, ZZCanvasView.java, ZZKeyBindings1.java, + ZZObsTrigger.java, ZZPrimitiveActions.java, ZZViewComponent.java, + part/VersionPart.java: merge from 0.6 + +2001-04-17 Tuesday 15:47 Benjamin Fallenstein + + * Java/: EditCursor.java, ZZCursorReal.java: More edit cursor stuff + +2001-04-17 Tuesday 11:25 Benjamin Fallenstein + + * Java/: media/FText.java, flob/SplitCellFlob1.java: Allow + arbitrary handles (== objects returned by hit()) for SplitCellFlobs + and FText.CellParts + +2001-04-16 Monday 21:33 Benjamin Fallenstein + + * Java/: EditCursor.java, ZZCursorReal.java: Edit cursor stuff + (ZZPrimitiveActions hasn't been converted yet) + +2001-04-16 Monday 10:44 Benjamin Fallenstein + + * Java/ZZPrimitiveActions.java: Oops. (removed a part that would've + prevented compiling). Now, the change in ZZPrimitiveActions is that + all actions using VStream are removed. + +2001-04-16 Monday 10:37 Benjamin Fallenstein + + * Java/ZZPrimitiveActions.java, + Modules/zaubertrank/ZaubertrankCellView.java: More Archimedes + fiddling + +2001-04-15 Sunday 16:26 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankCellView.java: More tuning on + Archimedes/the zaubertrank connection + +2001-04-15 Sunday 14:18 Benjamin Fallenstein + + * Java/flob/SplitCellFlob1.java, Java/media/FText.java, + Modules/zaubertrank/ZaubertrankCellView.java: Make the zaubertrank + work somewhat together with Archimedes + +2001-04-15 Sunday 11:01 Tuomas J. Lukka + + * Java/media/VStream.java: Remove VStream.java + +2001-04-15 Sunday 11:00 Tuomas J. Lukka + + * Java/p2p/: P2PStorage.java, P2PStorageCache.java, UniqueID.java: + Small changes + +2001-04-13 Friday 22:40 Benjamin Fallenstein + + * Java/ZZKeyHacks.java: Oops... and huh? + +2001-04-13 Friday 22:38 Benjamin Fallenstein + + * Java/ZZKeyBindings1.java: Another input event hack, this time for + the Macintosh mouse (convert no button --> Button 1, and when the + Meta key is down (Apple key on Macs), use Button 3 bindings which + are quite important in GZZ.) + +2001-04-13 Friday 21:47 Kimmo Wideroos + + * Java/flob/: BeamDecor2.java, SimpleBeamer2.zob: + oops! fixed class naming - hope it works now. Thanks Benja for + mentioning! + +2001-04-12 Thursday 11:26 Kimmo Wideroos + + * Modules/awtool/: AwtNileView.java, AwtUtil.java, AwtView1.java, + Awtool.java, Awtool.zob, README: Resizing, Nile transclusion etc. + +2001-04-12 Thursday 09:23 Kimmo Wideroos + + * Java/flob/: BeamDecor2.java, SimpleBeamer2.zob: Instead of filled + beams draw frames around transcluded textchunks. + +2001-04-09 Monday 09:19 Antti-Juhani Kaijanaho + + * manifest-filter.lst (ver_0_6): don't include manuscripts in + releases + +2001-04-08 Sunday 18:12 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): remove multimedia, virtualcommunity & + java2d from jar build + +2001-04-08 Sunday 17:07 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): add jar arch support + +2001-04-08 Sunday 17:00 Antti-Juhani Kaijanaho + + * Modules/virtualcommunity/MessageFlobFactory.zob (ver_0_6): make + vc compile + +2001-04-08 Sunday 16:36 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): add virtualcommunity and multimedia back + to jars + +2001-04-08 Sunday 16:24 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java (ver_0_6): fix + +2001-04-08 Sunday 16:18 Benjamin Fallenstein + + * NEWS (ver_0_6): Add umlaut bugfix + +2001-04-08 Sunday 16:13 Antti-Juhani Kaijanaho + + * Java/ZZObsTrigger.java (ver_0_6): fix a lame bug (causes null + pointer exceptions) + +2001-04-08 Sunday 15:49 Benjamin Fallenstein + + * Java/: ZZPrimitiveActions.java, ZZPrimitiveActions.java + (ver_0_6): Fix + +2001-04-08 Sunday 15:36 Antti-Juhani Kaijanaho + + * NEWS (ver_0_6): update + +2001-04-08 Sunday 15:17 Benjamin Fallenstein + + * Java/: ZZKeyHacks.java, ZZPrimitiveActions.java (ver_0_6): Use + Unicode character range instead of some predefined characters + +2001-04-08 Sunday 15:16 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): add it here too + +2001-04-08 Sunday 15:11 Benjamin Fallenstein + + * Java/Makefile: Add the zaubertrank to JARMODULES + +2001-04-08 Sunday 15:07 Antti-Juhani Kaijanaho + + * Java/Makefile: fix BuildInfo building + +2001-04-08 Sunday 13:27 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): BAH! + +2001-04-08 Sunday 13:20 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): remove net from sources + +2001-04-08 Sunday 13:00 Benjamin Fallenstein + + * Java/: ZZCanvasView.java, ZZKeyBindings1.java, + ZZPrimitiveActions.java (ver_0_6): Background colors for modes + +2001-04-08 Sunday 13:00 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): remove multimedia from jarmodules + +2001-04-08 Sunday 12:56 Tuomas J. Lukka + + * Modules/textcloud/TextCloud.zob: Textcloud is not compatible with + intended changes - will need to be rewritten later + +2001-04-08 Sunday 12:50 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_6): remove virtualcommunity from jarmodules + +2001-04-08 Sunday 11:50 Benjamin Fallenstein + + * Java/ZZKeyHacks.java: file ZZKeyHacks.java was initially added on + branch ver_0_6. + +2001-04-08 Sunday 11:50 Benjamin Fallenstein + + * Java/: ZZKeyHacks.java, ZZViewComponent.java (ver_0_6): The + umlaut hack detecting VM behavior + +2001-04-07 Saturday 18:17 Tuomas J. Lukka + + * Java/media/: ZZDefaultText.java, ZZText.java: Remove: this should + be done with cell content applitudes. + +2001-04-05 Thursday 15:14 Benjamin Fallenstein + + * Modules/vob/: View.java, Vob.java, VobSet.java, VobStore.java: We + can get rid of these anyway. + +2001-04-05 Thursday 13:27 Tuomas J. Lukka + + * Modules/: nile/draft/Nile3Unit.java, vob/Vob.java: Make 1.3 + javadoc work again. + +2001-04-05 Thursday 13:24 Tuomas J. Lukka + + * Modules/vob/Connection.java: What in the world was that? + +2001-04-05 Thursday 08:54 Antti-Juhani Kaijanaho + + * Java/Makefile: an experimental target for native compilation + using GCC Java + +2001-04-04 Wednesday 18:10 Tuomas J. Lukka + + * Java/: Makefile, media/ImageSpan.java, p2p/P2PStorage.java, + p2p/P2PStorageCache.java, p2p/UniqueID.java: More p2p stuff. + StorageCache is already outdated + +2001-04-04 Wednesday 18:09 Tuomas J. Lukka + + * Java/storage/DummyStreamSet.java, Modules/applet/ZZApplet.java: + Id + +2001-04-03 Tuesday 15:29 Benjamin Fallenstein + + * NEWS: Update + +2001-04-03 Tuesday 15:28 Benjamin Fallenstein + + * Java/ZZDefaultSpace.java: Add multiline cell view and quad view + to standard views/cell views (quad because currently you can see + multiline only there). + +2001-04-03 Tuesday 15:02 Benjamin Fallenstein + + * Java/: ZZDefaultSpace.java, ZZKeyBindings1.java, + ZZPrimitiveActions.java: Add support for cellview-specific + bindings; however, this isn't very useful until we have seperate + view and edit cursors, too... + +2001-04-03 Tuesday 11:23 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/mediaserver.tex: New ID format + +2001-04-03 Tuesday 08:59 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/mediaserver.tex: A draft spec for the + storage module HTTP interface + +2001-04-02 Monday 20:32 Benjamin Fallenstein + + * Java/Makefile: Add zaubertrank to modules + +2001-04-02 Monday 20:30 Benjamin Fallenstein + + * Modules/zaubertrank/: Actions.java, Evaluator.java, + ParsedView.zob, Parser.java, Primitive.java, PrimitiveSet.java, + SimpleView.zob, TokenFlob.java, TokenGrouper.java, + Zaubertrank.java, ZaubertrankPart.java: Move + +2001-04-02 Monday 20:29 Benjamin Fallenstein + + * Modules/zaubertrank/old/: Actions.java, Evaluator.java, + ParsedView.zob, Parser.java, Primitive.java, PrimitiveSet.java, + SimpleView.zob, TokenFlob.java, TokenGrouper.java, + Zaubertrank.java, ZaubertrankPart.java: Move old crud + +2001-04-02 Monday 20:23 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankCellView.java: Another cell view + for the zaubertrank, showing a tree of assembled tokens + +2001-04-02 Monday 20:21 Benjamin Fallenstein + + * Java/flob/SplitCellFlob1.java: Fix even more + +2001-04-02 Monday 20:20 Benjamin Fallenstein + + * Java/flob/FTextCellView.zob: fix more + +2001-04-02 Monday 20:02 Benjamin Fallenstein + + * Java/: flob/RankTextView.zob, flob/SimpleTextView.zob, + media/FText.java: Show cursors again + +2001-04-02 Monday 20:00 Benjamin Fallenstein + + * Java/flob/SplitCellFlob1.java: Do show backgrounds during + interpolation + +2001-04-02 Monday 19:31 Benjamin Fallenstein + + * Java/: flob/FTextCellView.zob, media/FText.java: Fix + FTextCellView.getSize() + +2001-04-02 Monday 17:23 Tuomas J. Lukka + + * Java/p2p/: P2PStorage.java, UniqueID.java: Add ids + +2001-04-02 Monday 17:22 Tuomas J. Lukka + + * Documentation/Mediaserver/mediaserver.tex: Rm code + +2001-04-02 Monday 16:59 Benjamin Fallenstein + + * Java/flob/FTextCellView.zob: Small fix (pass rootclone to + getFText()). + +2001-04-02 Monday 16:38 Benjamin Fallenstein + + * Java/ZZCursorReal.java: A method in ZZCursorReal to get the color + of the first colored cursor accursing a cell. + +2001-04-02 Monday 10:09 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/mediaserver.tex: Some crypto + +2001-04-01 Sunday 17:45 Benjamin Fallenstein + + * Modules/zaubertrank/TokenTextCellView.java: A cell view for + zaubertrank token text editing. + +2001-04-01 Sunday 15:47 Tuomas J. Lukka + + * Java/p2p/: P2PStorage.java, UniqueID.java: Add mediaserver apis + +2001-04-01 Sunday 15:46 Tuomas J. Lukka + + * Java/storage/DummyStreamSet.java, Modules/applet/ZZApplet.java: + Separate dummystreamset + +2001-04-01 Sunday 11:38 Tuomas J. Lukka + + * Modules/benchmark/: GraphBench.java, ZZBench.java, + java2d/Java2DBench.java: Some extra tests + +2001-03-31 Saturday 13:31 Tuomas J. Lukka + + * Documentation/Mediaserver/mediaserver.tex: Add id + +2001-03-31 Saturday 13:30 Tuomas J. Lukka + + * Documentation/Mediaserver/mediaserver.tex: Some more + +2001-03-31 Saturday 13:26 Tuomas J. Lukka + + * Documentation/Mediaserver/mediaserver.tex: Indents + +2001-03-31 Saturday 13:23 Tuomas J. Lukka + + * Documentation/Mediaserver/mediaserver.tex: Architecture + +2001-03-30 Friday 17:21 Benjamin Fallenstein + + * Java/flob/FTextCellView.java: Yuck + +2001-03-30 Friday 16:19 Benjamin Fallenstein + + * Java/flob/: .cvsignore, CellFlobFactory1.zob, FTextCellView.java, + FTextCellView.zob, FTextLayouter.zob, SplitCellFlob1.java: An + FText-based cell view doing multiline; fixes. Note that + SplitCellFlobs won't show cursors in their backgrounds any more. + Need to fix this for RankTextView probably. (However, for 'real' + applications it just got in the way before.) + +2001-03-30 Friday 13:26 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/mediaserver.tex: Some ideas, including + a way to decentralizedly guarantee unique IDs. + +2001-03-30 Friday 10:33 Antti-Juhani Kaijanaho + + * NEWS: Update + +2001-03-30 Friday 10:30 Antti-Juhani Kaijanaho + + * changelog-authors: fix wikikr + +2001-03-29 Thursday 13:06 Antti-Juhani Kaijanaho + + * Java/: CommandLineOptionsParser.java, Main.java: a new + command-line options parser, closes task#20858 + +2001-03-28 Wednesday 08:37 Antti-Juhani Kaijanaho + + * Java/ZZDefaultSpace.java: Fix Tuomas' fix. + +2001-03-28 Wednesday 07:03 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/mediaserver.tex: More TeXification + +2001-03-28 Wednesday 06:48 Antti-Juhani Kaijanaho + + * Documentation/Mediaserver/mediaserver.tex: Fix LaTeX + +2001-03-28 Wednesday 06:47 Antti-Juhani Kaijanaho + + * Documentation/: mediaserver, Mediaserver/mediaserver.tex: TeXify + mediaserver + +2001-03-28 Wednesday 06:32 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: Remove a comment. + +2001-03-28 Wednesday 05:55 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: Some tinkering of + the abstract + the length requirement for the abstract + +2001-03-27 Tuesday 20:43 Tuomas J. Lukka + + * Documentation/mediaserver, Java/ZZDefaultSpace.java, + Modules/sound/Player.java, Modules/sound/SimplePlayer.java, + Modules/sound/Sound.java: Cleanup, fixes. Add new mediaserver doc + +2001-03-26 Monday 14:39 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Mods. + +2001-03-26 Monday 14:24 Tuomas J. Lukka + + * Documentation/Manuscripts/ZZTech/zztech.tex: Draft abstract + +2001-03-26 Monday 12:41 Tuomas J. Lukka + + * Java/ZZDrawing.java, Java/arch/java2d/ZZDrawingJ2D.java, + Modules/benchmark/GraphBench.java, Modules/benchmark/ZZBench.java, + Modules/benchmark/java2d/Java2DBench.java: Add new benchmarks. Very + instructive to run on a couple of different JVMs + +2001-03-25 Sunday 12:06 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: Small touches + +2001-03-23 Friday 08:30 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: A small comment on + versioning. + +2001-03-21 Wednesday 20:03 Tuomas J. Lukka + + * Java/Makefile, Modules/benchmark/README, + Modules/benchmark/ZZBench.java: Benchmarking JVMs. Sun 1.3 vs IBM + 1.3 is interesting... + +2001-03-21 Wednesday 10:01 Antti-Juhani Kaijanaho + + * Java/media/UTF8Char.java: c.b starts at 0, not at start. + embarrassing. + +2001-03-20 Tuesday 11:08 Antti-Juhani Kaijanaho + + * Java/flob/BoxedFlob.java: from Benja + +2001-03-20 Tuesday 09:45 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex, + Java/exp/rast/vanishing.view: MOre constr + +2001-03-19 Monday 07:31 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Add point + +2001-03-18 Sunday 20:22 Tuomas J. Lukka + + * Java/net/: ReliableUDPMessage.java, + ReliableUDPMessageFactory.java, ReliableUDPSocket.java: Reformat + and add doc + +2001-03-18 Sunday 20:21 Antti-Juhani Kaijanaho + + * Java/net/Peer.java: Document Peer. + +2001-03-18 Sunday 19:31 Antti-Juhani Kaijanaho + + * Java/net/: ReliableUDPMessage.java, + ReliableUDPMessageFactory.java, ReliableUDPSocket.java: some + documentation on the reliable UDP scheme + +2001-03-18 Sunday 17:50 Benjamin Fallenstein + + * Java/flob/BoxType.java, Java/flob/CellFlob1.java, + Java/flob/FlobSet.java, Java/flob/SceneFlob.java, + Java/flob/SimpleBoxType.java, Java/flob/SimpleSceneFlob.java, + Java/flob/WindowCellView.zob, + Modules/daytimedemo/ClockCellView.zob: Now make regular background + colors for BoxType boxes work. At the same time, move CellFlobs to + use BoxTypes. -- ATTN: Changing CellFlob1's superclass breaks + binary compatibility again... + +2001-03-18 Sunday 11:04 Benjamin Fallenstein + + * Java/flob/FlobSet.java: Aforementioned bug fixed. + +2001-03-18 Sunday 10:38 Benjamin Fallenstein + + * Java/flob/IdiosyncraticFlobFactory.zob, + Java/flob/WindowCellView.zob, + Modules/daytimedemo/ClockCellView.zob: Idiosyncratic should search + the cell view at the root clone, so that e.g. clocks and windows + (in the examples) can be cloned. There's a BUG though which haven't + been able to track down yet: showing two clones of the same thing + at the same time causes the update loop to stop. + +2001-03-17 Saturday 23:08 Benjamin Fallenstein + + * Java/flob/: BoxType.java, Flob.java, FlobSet.java, + SimpleBoxType.java, SimpleSceneFlob.java: An interface separating + frame/bg rendering from content rendering, currently drawing the + same background/frame as CellBgFlob. Used to give the window cell + view cells a real frame. They don't look that bad now. + +2001-03-17 Saturday 22:12 Benjamin Fallenstein + + * Java/flob/: .cvsignore, SimpleSceneFlob.java, WindowCellView.zob: + A cell view showing the contents of a window-- i.e., a window's + cursor cell is drawn as a SceneFlob regularly filled with that + window's view/contents. + +2001-03-17 Saturday 20:13 Benjamin Fallenstein + + * Java/flob/: FlobSet.java, Renderable.java, SceneFlob.java: Some + preparations for doing actual transpointing windows based on + SceneFlobs. ATTN: I have changed FlobSet.DepthIter from an + interface to an abstract class. This doesn't change the source, + because DepthIter is always implemented/subclassed anonymously, but + it breaks binary compatibility. + +2001-03-17 Saturday 11:17 Benjamin Fallenstein + + * Java/flob/SimpleSceneFlob.java, Modules/daytimedemo/.cvsignore, + Modules/daytimedemo/ClockCellView.zob, + Modules/daytimedemo/DayTimeDemo.zob: In order to get familiar with + the SceneFlob code, a simple demo showing cells as daytimedemo + clocks (i.e. a cell view for use with idiosyncratic) + +2001-03-16 Friday 14:46 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: The "explanation of + GZigZag"-part should be much better now. + +2001-03-16 Friday 14:15 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Quite heavy mods. + +2001-03-16 Friday 12:33 Kimmo Wideroos + + * Documentation/Manuscripts/: gzigzag.bib, Awt/Makefile, + Awt/awt.tex, Awt/awtf.tex, Awt/ht01e.sty: Started a shortpaper on + awt concept map demo. My latex skills are 0, so I had to "borrow" + some tex-stuff from HyperRFC-article. Thanks Tuomas, Rauli, Vesa + and AJK ;) + +2001-03-16 Friday 12:19 Kimmo Wideroos + + * Modules/awtool/: AwtCursor.java, AwtMetrics.java, AwtMetrics.zob, + AwtNileView.java, AwtUtil.java, AwtView1.java, Awtool.java, + Awtool.zob: Nile embedded. If you want to try it out, change + between Nile and Awtool by 'Alt-N'. This is preliminary work, only + basic Nile actions "tested". + +2001-03-15 Thursday 19:24 Antti-Juhani Kaijanaho + + * Java/: Makefile, net/Peer.java, net/ReliableUDPMessage.java, + net/ReliableUDPMessageFactory.java, net/ReliableUDPSocket.java: an + untested but compilable Reliable UDP implementation + +2001-03-15 Thursday 16:50 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Better paragraph 2? (rest of + the document doesn't work at all) + +2001-03-15 Thursday 15:50 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Minor mod to paragraph 2. + +2001-03-15 Thursday 14:37 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Bureaucracy. + +2001-03-14 Wednesday 20:10 Benjamin Fallenstein + + * Documentation/Manuscripts/ZZTech/zztech.tex: More versioning + comments + +2001-03-14 Wednesday 07:13 Antti-Juhani Kaijanaho + + * Java/ZZLogger.java: Emphasize that logfile is null at startup. + +2001-03-13 Tuesday 15:30 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: More bureaucracy. + +2001-03-12 Monday 14:03 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Twid + +2001-03-12 Monday 13:38 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: More + +2001-03-12 Monday 13:32 Rauli Ruohonen + + * Documentation/misc/byrokratiadoku: Added a terrible byrocratic + document (in Finnish). Hopefully it drops off the edge of the hard + disk soon. + +2001-03-12 Monday 11:08 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/: Makefile, raster.tex: More + +2001-03-12 Monday 06:04 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: Some thoughts about + version persistency and branching. + +2001-03-11 Sunday 19:14 Vesa Parkkinen + + * Java/media/Span.java, Modules/sound/Player.java, + Modules/sound/Recorder.java, Modules/sound/SimplePlayer.java, + Modules/sound/SimpleRecorder.java, Modules/sound/Sound.java, + Modules/sound/gsm_def.h, Modules/sound/gsm_player.c, + Modules/sound/gsm_recorder.c, + Modules/sound/org_gzigzag_module_SimplePlayer.h, + Modules/sound/org_gzigzag_module_SimpleRecorder.h, + Modules/sound/ZZPlayer.java: some sound stuff + +2001-03-11 Sunday 10:41 Kimmo Wideroos + + * Modules/awtool/: AwtUtil.java, AwtView1.java, Awtool.java, + Awtool.zob: bugfixes, got rid of some unnecessary variables + +2001-03-10 Saturday 10:32 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: oops + +2001-03-10 Saturday 10:31 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Index changes + +2001-03-09 Friday 13:34 Tuomas J. Lukka + + * Documentation/Manuscripts/gzigzag.bib: Add more constr refs + +2001-03-09 Friday 08:54 Tuomas J. Lukka + + * Documentation/Manuscripts/: gzigzag.bib, Rasters/raster.tex: Add + constr refs + +2001-03-08 Thursday 15:05 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Some more + +2001-03-08 Thursday 15:05 Tuomas J. Lukka + + * CODING: Document exp + +2001-03-08 Thursday 13:54 Antti-Juhani Kaijanaho + + * Java/: part/VersionPart.java, storage/ZZCacheDimSpace.java: + AAARGH + +2001-03-08 Thursday 13:37 Antti-Juhani Kaijanaho + + * Java/: ZZSpacePart.java, part/VersionPart.java, + storage/ZZCacheDimSpace.java: make rest of the triggers work + (hopefully) + +2001-03-08 Thursday 10:50 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: Oops + +2001-03-08 Thursday 10:48 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: Mostly fix triggering; + rationalization + +2001-03-07 Wednesday 12:57 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: hm + +2001-03-07 Wednesday 12:51 Antti-Juhani Kaijanaho + + * Java/: ZZDimSpace.java, part/VersionPart.java: make old-dimension + connections along versioned regular dimensions truly immutable + +2001-03-07 Wednesday 12:06 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: simplify the fix + +2001-03-07 Wednesday 12:05 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: active-versions dimension + a bugfix + for the versioned regular dims + +2001-03-06 Tuesday 14:22 Antti-Juhani Kaijanaho + + * Makefile: split ChangeLog + +2001-03-06 Tuesday 14:09 Antti-Juhani Kaijanaho + + * changelog-authors: add wikikr to changelog-authors + +2001-03-06 Tuesday 14:05 Antti-Juhani Kaijanaho + + * NEWS: update + +2001-03-06 Tuesday 13:44 Antti-Juhani Kaijanaho + + * NEWS, Java/Main.java, Java/storage/ContentHash.java, + Java/storage/DimHash.java, Java/storage/DirSet.java, + Java/storage/Recs.pl, Java/storage/TestDimHash.java, + Java/storage/WritableHash.java, Java/storage/WritableIS.java, + Java/storage/WritableSet.java, + Java/storage/ZZPersistentDimSpace.java, + Java/storage/ZZPersistentDimension.java, + Java/transform/Convert.java: removing PersistentDimSpace and + associated cruft + +2001-03-06 Tuesday 13:36 Antti-Juhani Kaijanaho + + * cvsparser.pl: oops + +2001-03-06 Tuesday 13:32 Antti-Juhani Kaijanaho + + * cvsparser.pl, cvsparser.pl: fix Manifest making when files are + marked as deleted + +2001-03-05 Monday 14:44 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Name the first + restricted model + +2001-03-05 Monday 14:44 Tuomas J. Lukka + + * Java/exp/rast/vanishing.view: Experimental hypothetical code for + vanishing view in a declarative way + +2001-03-05 Monday 11:01 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/Rasters/: raster.tex, raster.tex: Bah + +2001-03-05 Monday 10:56 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/Rasters/raster.tex: More fixes + +2001-03-05 Monday 10:45 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: ? + +2001-03-05 Monday 10:42 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/Rasters/raster.tex: More the same. + +2001-03-05 Monday 10:40 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/Rasters/raster.tex: Improve the LaTeX + +2001-03-05 Monday 10:10 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: more + +2001-03-05 Monday 10:03 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/: gzigzag.bib, HyperRFC/Makefile, + HyperRFC/hyp.bib, HyperRFC/hyp.tex: use common bib database + +2001-03-05 Monday 08:44 Tero Mäyränen + + * Modules/multimedia/: MediaFlobView.java, MediaMath.java, + MediaZOb.java, Pixels.java, PolygonRenderer.java, Polygons.java, + adjust.java, crop.java, dots.java, mm.java, move.java, readme.html, + rect.java, sin.java: a couple of new mediazobs + +2001-03-03 Saturday 18:24 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: More + +2001-03-03 Saturday 14:59 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: More + +2001-03-03 Saturday 14:43 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Grid is wrong name + +2001-03-03 Saturday 13:17 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: Some more, and + bugfix + +2001-03-03 Saturday 10:58 Tuomas J. Lukka + + * Documentation/Manuscripts/Rasters/raster.tex: More stuff. Now + actually showing one good example of why rasters and constraints + are important + +2001-03-02 Friday 16:00 Tuomas J. Lukka + + * Documentation/Manuscripts/: RFC2/rfc2.tex, Rasters/raster.tex, + ZZTech/zztech.tex: Rasters doc. More stuff + +2001-03-02 Friday 12:14 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/gzigzag.bib: Forgot Tarjan. + +2001-03-02 Friday 11:57 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/: gzigzag.bib, ZZTech/Makefile, + ZZTech/zztech.tex: references + +2001-03-02 Friday 07:13 Antti-Juhani Kaijanaho + + * Documentation/keybindings.wml: Document the panic button. + +2001-03-02 Friday 06:44 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: fix showing old connections along + regular dimensions + +2001-03-02 Friday 06:43 Antti-Juhani Kaijanaho + + * Java/ZZKeyBindings1.java: Fix panic button + +2001-03-02 Friday 00:30 Kimmo Wideroos + + * Modules/awtool/: AwtLink.java, AwtLink.zob, AwtMetrics.java, + AwtMetrics.zob, AwtMetricsFC.java, AwtMetricsFC2.java, + AwtMetricsNormal.java, AwtNote.java, AwtNote.zob, AwtUtil.java, + AwtView1.java, Awtool.java, Awtool.zob, BooleanMesh.java, README, + TODO, ZObCellRepr.java: Adding a new module: A(ssociative) writing + tool a (multilayered) concept map -demo + +2001-03-01 Thursday 13:56 Antti-Juhani Kaijanaho + + * Java/: Main.java, part/VersionPart.java: optionally show old + connections on regular dimensions + +2001-03-01 Thursday 13:53 Antti-Juhani Kaijanaho + + * Java/storage/GZZ0.java: Not writing / writing notifications are + good + +2001-03-01 Thursday 11:48 Antti-Juhani Kaijanaho + + * Java/ZZKeyBindings1.java: add a panic button + +2001-03-01 Thursday 10:21 Antti-Juhani Kaijanaho + + * Java/Makefile: remove multimedia from MODULES, as it requires + java2d + +2001-03-01 Thursday 10:20 Antti-Juhani Kaijanaho + + * Java/Makefile: remove virtualcommunity from MODULES, as it + requires java2d + +2001-03-01 Thursday 09:57 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: simplify TeX + +2001-03-01 Thursday 09:16 Antti-Juhani Kaijanaho + + * Java/: ZZDimSpace.java, storage/ZZCacheDimSpace.java: fix nextID + problem with -slurping + +2001-02-28 Wednesday 10:34 Tuomas J. Lukka + + * Documentation/Manuscripts/: MsgFoc/msgfoc.tex, ZZTech/zztech.tex: + Fixes + +2001-02-28 Wednesday 10:18 Tuomas J. Lukka + + * Modules/virtualcommunity/: MessageFlobFactory.zob, VCView2.java, + VCView4.java, VirtualCommunity.zob: Final fixes that were done + before morning demo. (I also tweaked the space to have different + parameter sets for view2). Vesa, take a look at this to understand + the flobset hierarchy and how I meant it on the phone. + +2001-02-28 Wednesday 05:16 Tuomas J. Lukka + + * Modules/: multimedia/image.java, + virtualcommunity/MessageFlobFactory.zob, + virtualcommunity/VCView2.java, virtualcommunity/VCView4.java, + virtualcommunity/VirtualCommunity.zob: Fixes + +2001-02-28 Wednesday 04:25 Vesa Parkkinen + + * Java/flob/SceneFlob.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VCView2.java, + Modules/virtualcommunity/VCView4.java, + Modules/virtualcommunity/VirtualCommunity.zob, + Modules/virtualcommunity/VirtualCommunity.zob: vc work + +2001-02-28 Wednesday 03:14 Tuomas J. Lukka + + * Modules/virtualcommunity/: MessageFlobFactory.zob, VCView2.java, + VirtualCommunity.zob: Rm debuging + +2001-02-28 Wednesday 03:02 Tuomas J. Lukka + + * Modules/: servlet/VCServlet.java, + virtualcommunity/VirtualCommunity.zob: Oops + +2001-02-28 Wednesday 02:16 Tuomas J. Lukka + + * Modules/virtualcommunity/: VCView2.java, VirtualCommunity.zob: + More parametrization + +2001-02-28 Wednesday 02:12 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: Small twiddles + +2001-02-28 Wednesday 01:43 Tuomas J. Lukka + + * Java/flob/FlobSet.java, Java/flob/SceneFlob.java, + Modules/virtualcommunity/VCView4.java: Select lod for vcview4 + +2001-02-28 Wednesday 01:03 Vesa Parkkinen + + * Modules/virtualcommunity/VCView4.java: more stuff to vc demo + +2001-02-28 Wednesday 01:01 Vesa Parkkinen + + * Modules/virtualcommunity/: VCView2.java, VCView4.java, + VirtualCommunity.zob: some stuff to vc demo + +2001-02-28 Wednesday 00:46 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java, Java/flob/FlobSet.java, + Java/flob/SceneFlob.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VirtualCommunity.zob: Whew. Selective + level-of-detail animation + +2001-02-27 Tuesday 23:55 Tuomas J. Lukka + + * Modules/: multimedia/image.java, + virtualcommunity/MessageFlobFactory.zob: Take tailer hack out. This + needs to be done right. + +2001-02-27 Tuesday 23:49 Vesa Parkkinen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, VCView1.java, + VCView2.java, VCView4.java, VirtualCommunity.zob: added products + +2001-02-27 Tuesday 23:32 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: explained a bit what + this paper is in the comments; moved beja's comment away from the + margin, it did not fit there + +2001-02-27 Tuesday 23:18 Tuomas J. Lukka + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Write down a thought + +2001-02-27 Tuesday 22:57 Tuomas J. Lukka + + * Modules/virtualcommunity/: VCView4.java, VirtualCommunity.zob: + vcview 4 + +2001-02-27 Tuesday 21:53 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: Fix vc2 when two children + +2001-02-27 Tuesday 21:12 Benjamin Fallenstein + + * Documentation/Manuscripts/ZZTech/zztech.tex: comment on + versioning (I hope the TeX code is correct, I've never used TeX) + +2001-02-27 Tuesday 21:08 Tuomas J. Lukka + + * Modules/virtualcommunity/: VCView2.java, VirtualCommunity.zob: + More depth + +2001-02-27 Tuesday 20:45 Tuomas J. Lukka + + * Modules/virtualcommunity/VirtualCommunity.zob: Without rotation + :( + +2001-02-27 Tuesday 20:39 Tuomas J. Lukka + + * Modules/virtualcommunity/: MessageFlobFactory.zob, VCView2.java, + VirtualCommunity.zob: Text doing a little different + +2001-02-27 Tuesday 20:31 Tuomas J. Lukka + + * Modules/virtualcommunity/MessageFlobFactory.zob: Now leave out if + center outside screen. Too much, but faster + +2001-02-27 Tuesday 20:26 Tuomas J. Lukka + + * Modules/virtualcommunity/: VCView2.java, VirtualCommunity.zob: + lisaa + +2001-02-27 Tuesday 20:04 Antti-Juhani Kaijanaho + + * Java/storage/GZZ0.java: add id to ZZFatalError + +2001-02-27 Tuesday 20:03 Vesa Parkkinen + + * Modules/virtualcommunity/VirtualCommunity.zob: added vcview3 + +2001-02-27 Tuesday 20:02 Antti-Juhani Kaijanaho + + * Java/storage/CountingStream.java: Fix. + +2001-02-27 Tuesday 20:02 Vesa Parkkinen + + * Modules/virtualcommunity/VCView3.java: added + +2001-02-27 Tuesday 20:00 Tuomas J. Lukka + + * Java/storage/CountingStream.java: ARGH + +2001-02-27 Tuesday 19:57 Tuomas J. Lukka + + * Java/storage/GZZ0.java: Countingstream + appl + +2001-02-27 Tuesday 19:12 Tuomas J. Lukka + + * Modules/virtualcommunity/: VCView2.java, VirtualCommunity.zob: + Temporary: don't render out-of-sight msgflobs. But have to do this + in a different place in reality + +2001-02-27 Tuesday 17:12 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: Better view2 + +2001-02-27 Tuesday 16:27 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Removed the red + letters. + +2001-02-27 Tuesday 16:19 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: getHeight testing + +2001-02-27 Tuesday 16:12 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Bugfixes. + +2001-02-27 Tuesday 16:02 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: Better + +2001-02-27 Tuesday 15:43 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Bugfix. + +2001-02-27 Tuesday 15:35 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: Parempi + +2001-02-27 Tuesday 15:34 Tuomas J. Lukka + + * Modules/virtualcommunity/: VCView2.java, VirtualCommunity.zob: + View2 primitively works + +2001-02-27 Tuesday 15:15 Rauli Ruohonen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, + VirtualCommunity.zob: In the middle of a bugfix to getHeight() in + MFF. + +2001-02-27 Tuesday 14:35 Tuomas J. Lukka + + * Modules/virtualcommunity/VCView2.java: Ups + +2001-02-27 Tuesday 14:10 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Fixes. + +2001-02-27 Tuesday 14:06 Tuomas J. Lukka + + * Modules/virtualcommunity/: MessageFlobFactory.zob, VCView1.java, + VCView2.java, VirtualCommunity.zob: Second view. Some small + twiddles elsewhere + +2001-02-27 Tuesday 13:40 Rauli Ruohonen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, VCView1.java, + VirtualCommunity.zob: Text animation intermediate commit. + +2001-02-27 Tuesday 13:02 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Coloring stuff + to VC + +2001-02-27 Tuesday 12:29 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Antialiasing + outline during animation. (VC) + +2001-02-27 Tuesday 12:10 Rauli Ruohonen + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Added use of + "VALUE_RENDER_SPEED" to ZZDJ2D, and a getSize() cache to MFF. + +2001-02-27 Tuesday 11:48 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: More height + stuff to VC. + +2001-02-27 Tuesday 11:35 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: + MessageFlobFactory: Calculation of height stuff. + +2001-02-27 Tuesday 10:55 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/virtualcommunity/VCView1.java, + Modules/virtualcommunity/VirtualCommunity.zob: Move material around + - now easy to make new vc views + +2001-02-27 Tuesday 10:43 Rauli Ruohonen + + * Modules/virtualcommunity/MessageFlobFactory.zob: Removed + subj/auth drawing from animation. + +2001-02-27 Tuesday 08:42 Rauli Ruohonen + + * Java/ZZDrawing.java, Java/arch/java2d/ZZDrawingJ2D.java, + Modules/multimedia/MediaFlobFactory.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Enabled image + drawing only when qualityEnabled(). + +2001-02-27 Tuesday 08:36 Rauli Ruohonen + + * Java/ZZCanvasView.java, Java/ZZDrawing.java, + Java/ZZUpdateManager.java, Java/arch/java2d/ZZDrawingJ2D.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Cleaned up "draw + last frame twice" - now it does it once w/ setQuality() disabled + and right afterwards with it enabled. Commented out most of the + disables from VC demo. (but it still renders text too slowly) + +2001-02-27 Tuesday 06:14 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: Some ideas. + +2001-02-26 Monday 21:21 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VirtualCommunity.zob: Fix rotated flob + interpolation. Messageflobs must always be rotatedflobs but we + needn't rotate unless rotated (clear?) + +2001-02-26 Monday 20:48 Rauli Ruohonen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, + VirtualCommunity.zob: Committed rotation changes to VC. + +2001-02-26 Monday 20:00 Rauli Ruohonen + + * Java/ZZCanvasView.java, Java/ZZUpdateManager.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Added back text + display in VC. Added renderInterp() call at 1.0 frames. + +2001-02-26 Monday 19:45 Rauli Ruohonen + + * Modules/: multimedia/MediaFlobFactory.java, + virtualcommunity/MessageFlobFactory.zob: Stripped down displaying + of almost everything from VC demo to get speed. (will be added + back later) + +2001-02-26 Monday 18:42 Rauli Ruohonen + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/multimedia/MediaFlobFactory.java: Mod:ed the kludge a bit. + +2001-02-26 Monday 18:29 Rauli Ruohonen + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/multimedia/MediaFlobFactory.java: Added a kludge to disable + antialiasing during image drawing + +2001-02-26 Monday 18:14 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java: Doc + +2001-02-26 Monday 18:12 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java: Fix rotation interpolation: + center was wrong + +2001-02-26 Monday 18:03 Rauli Ruohonen + + * Java/arch/java2d/ZZDrawingJ2D.java, Java/flob/CellBgFlob.java, + Java/flob/SplitCellFlob1.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Removed some + clipping + added a quality hint (J2D). + +2001-02-26 Monday 16:40 Rauli Ruohonen + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Fixed a bug in J2D + (AffineTransform w/ wrong anchor point) and VirtualCommunity + (clicking "Author" no longer does anything + all clipping is + removed [this part is not a bugfix, but a bugintroduction :-)]). + +2001-02-26 Monday 16:03 Rauli Ruohonen + + * Java/arch/java2d/ZZDrawingJ2D.java, + Modules/multimedia/MediaFlobFactory.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Bugfixes. Demo + does rotation. (but doesn't work w/o java2d for now) + +2001-02-26 Monday 15:43 Tero Mäyränen + + * Modules/multimedia/: MediaZOb.java, readme.html: Added macrostuff + +2001-02-26 Monday 15:41 Rauli Ruohonen + + * Java/Makefile, Java/flob/FlobSet.java, + Modules/multimedia/MediaFlobFactory.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Fixed some + breakages of the last commit. Broke MessageFlobFactory. + +2001-02-26 Monday 14:57 Rauli Ruohonen + + * Java/ZZDimSpace.java, Java/ZZObsTrigger.java, + Java/ZZViewComponent.java, Java/flob/FlobSet.java, + Java/media/FText.java, Modules/multimedia/MediaFlobFactory.java, + Modules/multimedia/MediaZOb.java, Modules/multimedia/image.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VirtualCommunity.zob: Made the + virtualcommunity demo cuter; fixed bugs in multimedia module, + ZZDimSpace, FlobSet, FText, worked around a JVM implementation one + in ZZViewComponent. + +2001-02-26 Monday 14:55 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java: Oops, we want center, not + origin rotation + +2001-02-26 Monday 14:53 Tuomas J. Lukka + + * Java/: arch/java2d/ZZDrawingJ2D.java, flob/SceneFlob.java: + Untested rotated subflobset code. + +2001-02-26 Monday 14:43 Tuomas J. Lukka + + * Java/flob/SceneFlob.java: Sceneflob more + +2001-02-26 Monday 14:29 Tuomas J. Lukka + + * Java/flob/SceneFlob.java: New flob type that can contain other + flobs. You may have guessed - this is for rotation. + +2001-02-26 Monday 14:08 Tuomas J. Lukka + + * Documentation/Manuscripts/ZZTech/zztech.tex: some items + +2001-02-26 Monday 14:04 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: *Very* minimal + structure. + +2001-02-26 Monday 13:16 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: tweak + +2001-02-26 Monday 13:10 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/ZZTech/zztech.tex: initial rev + +2001-02-26 Monday 12:58 Tuomas J. Lukka + + * Documentation/Manuscripts/RFC2/rfc2.tex: Start + +2001-02-26 Monday 12:36 Tuomas J. Lukka + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Some fixes + +2001-02-26 Monday 10:29 Tuomas J. Lukka + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Outline. Please read + and comment + +2001-02-26 Monday 10:13 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: version:list->version:active, add + benja's version:list + +2001-02-26 Monday 10:11 Tuomas J. Lukka + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Fix + +2001-02-26 Monday 08:23 Tuomas J. Lukka + + * Modules/virtualcommunity/MessageFlobFactory.zob: Add vile java + mode + +2001-02-24 Saturday 08:55 Tero Mäyränen + + * Modules/multimedia/: ImageSource.java, flobcolors.java, + text.java: This commit will hopefully remove some old files. + +2001-02-23 Friday 15:01 Tuomas J. Lukka + + * Java/Makefile: Remove multimedia from main makefile as it's + broken. + +2001-02-23 Friday 15:01 Tuomas J. Lukka + + * Java/media/TestLines.java: Remove 8-bit char string --- jikes + didn't like ISO-Latin1. + +2001-02-23 Friday 13:57 Benjamin Fallenstein + + * Java/part/VersionPart.java: A little interface enhancement: the + dimension version:d.xxx shows the connections of a cell along d.xxx + no matter which version it is from (only works for dimensions + prefixed by 'd.') + +2001-02-23 Friday 13:47 Antti-Juhani Kaijanaho + + * Java/part/VersionPart.java: Heavy commenting and documenting. + +2001-02-23 Friday 12:20 Benjamin Fallenstein + + * Java/: ZZSpace.java, part/VersionPart.java: Fix to compile with + javac: No static members in inner classes; and error messages that + ZZSpace.readonly isn't initialized in the constructors. I can't + explain that latter one, but to compile I've just un-finalized + readonly. Someone who understands these matters better please look + into it and find a clean solution. + +2001-02-23 Friday 08:33 Antti-Juhani Kaijanaho + + * Java/: ZZCellHandle.java, ZZDefaultSpace.java, ZZDimSpace.java, + ZZSpace.java, ZZSpacePart.java, storage/ZZCacheDimSpace.java, + storage/ZZCacheDimension.java, storage/ZZPersistentDimSpace.java, + part/VersionPart.java: accessing past versions works now + +2001-02-22 Thursday 16:26 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Fix. + +2001-02-22 Thursday 16:26 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Modernize the LaTeX + a little :-) + +2001-02-22 Thursday 16:16 Tuomas J. Lukka + + * Documentation/Manuscripts/MsgFoc/msgfoc.tex: Outline next article + +2001-02-22 Thursday 15:46 Tuomas J. Lukka + + * Java/: ZZDrawing.java, arch/java2d/ZZDrawingJ2D.java, + flob/FlobSet.java: Try rotation under 1.3. This code needs to be + disabled (made to check for e.g. a Java property on whether to + activate) before release... + +2001-02-22 Thursday 15:31 Tero Mäyränen + + * Modules/multimedia/: Default.java, MediaFlobFactory.java, + MediaZOb.java, Pixels.java, crop.java, dots.java, image.java, + mm.java, move.java, next.java, rect.java: A complete rewrite. + +2001-02-22 Thursday 15:27 Tuomas J. Lukka + + * Java/Main.java: Fix 1.3 ambiguity + +2001-02-22 Thursday 12:23 Antti-Juhani Kaijanaho + + * CODING: p and pa protected + +2001-02-21 Wednesday 06:11 Antti-Juhani Kaijanaho + + * Java/storage/ZZCacheDimSpace.java: dbg should not be final. + +2001-02-20 Tuesday 11:32 Antti-Juhani Kaijanaho + + * Java/: SpaceDump.java, ZZDimSpace.java: slurp works now + +2001-02-19 Monday 12:52 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More text + +2001-02-19 Monday 12:50 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Transpoint + +2001-02-19 Monday 12:50 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + Added clipping. + +2001-02-19 Monday 12:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/utopia.mp: Make connections + look more reasonable + +2001-02-19 Monday 12:44 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: another fix + +2001-02-19 Monday 12:38 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopia.mp: Lines. (incredibly + stupid-looking) + +2001-02-19 Monday 12:37 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: parallel + windows mockup + +2001-02-19 Monday 12:00 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopia.mp: Mods. + +2001-02-19 Monday 11:48 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/utopia.mp: Fix putitrot + +2001-02-19 Monday 11:38 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopia.mp: Still more buggy. + +2001-02-19 Monday 11:04 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + Buggy version for Tuomas. + +2001-02-19 Monday 09:57 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopia.mp: Rotatoin. + +2001-02-19 Monday 09:48 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopiapara.tex: A different + idea. + +2001-02-19 Monday 09:36 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopiapara.tex: Mods. + +2001-02-19 Monday 08:54 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + First draft of the left side. + +2001-02-19 Monday 08:40 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix + +2001-02-19 Monday 08:39 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix an overfull box. + +2001-02-19 Monday 08:00 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/utopiapara.tex: Oops. + +2001-02-19 Monday 07:54 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + Improvements to the fig. + +2001-02-19 Monday 07:51 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix + +2001-02-19 Monday 07:48 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fixes based on + Janne's comments. + +2001-02-19 Monday 07:45 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix abstract again ;) + +2001-02-19 Monday 07:42 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix some abstract. + +2001-02-19 Monday 07:40 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix quote formatting + +2001-02-19 Monday 07:37 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small fixes. + +2001-02-19 Monday 06:37 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Fix some underfull + boxen. + +2001-02-19 Monday 06:27 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix one more overfull + box + +2001-02-19 Monday 06:25 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: typos + +2001-02-19 Monday 06:24 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Deal with overfull + hboxen + +2001-02-19 Monday 06:02 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Updated a fig caption + +2001-02-19 Monday 05:55 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Typoes + +2001-02-19 Monday 05:49 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Typo + +2001-02-19 Monday 05:06 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Make figures slightly + smaller + +2001-02-19 Monday 04:48 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + Raulin muutoksia + +2001-02-19 Monday 04:25 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Lisaa... + +2001-02-19 Monday 03:43 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Another low-level + editing round + +2001-02-19 Monday 02:56 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Ok, now all text has + been gone through at least once today. + +2001-02-19 Monday 02:16 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: Makefile, hyp.bib, hyp.tex, + utopiapara.tex: Here's how to alter parwidth... Not pretty but it + works. + +2001-02-19 Monday 02:05 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.tex, utopia.mp, + utopiapara.tex: Changes. + +2001-02-19 Monday 00:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Rm old comments + +2001-02-19 Monday 00:21 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.tex, hyp.tex: More + low-level editing. + +2001-02-19 Monday 00:00 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Procedural -> + presentational + +2001-02-18 Sunday 23:59 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Edit little + +2001-02-18 Sunday 23:49 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More editing. + +2001-02-18 Sunday 23:32 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More work + +2001-02-18 Sunday 23:11 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Work on RFC intro + +2001-02-18 Sunday 23:06 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: fix some + references + +2001-02-18 Sunday 22:49 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: some ZZ + references + +2001-02-18 Sunday 22:40 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/utopiapara.tex: Fix spacing + +2001-02-18 Sunday 21:48 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Remove XXX to make + such references more obvious. + +2001-02-18 Sunday 21:46 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Emails + +2001-02-18 Sunday 21:43 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comments, fixes + +2001-02-18 Sunday 21:08 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fixes. + +2001-02-18 Sunday 21:00 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/utopiapara.tex: A complete + yuck(tm)-solution + +2001-02-18 Sunday 20:58 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/utopiapara.tex: Some fixes to + metapost. Table still doesn't work... + +2001-02-18 Sunday 20:39 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + [no log message] + +2001-02-18 Sunday 20:22 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Conclude more + +2001-02-18 Sunday 20:05 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.tex, utopiapara.tex: Fix + mp font + +2001-02-18 Sunday 20:01 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Start conclusions + +2001-02-18 Sunday 20:00 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + Diagram changes. + +2001-02-18 Sunday 19:57 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: More fixing. + +2001-02-18 Sunday 19:52 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: fix the + urls in bibtex db + +2001-02-18 Sunday 19:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move relwork again + +2001-02-18 Sunday 19:31 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More edits on + otherwork-refer + +2001-02-18 Sunday 19:19 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move hyperdocuments + in f+c to different place + +2001-02-18 Sunday 19:07 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Rmcrud + +2001-02-18 Sunday 18:24 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: utopia.mp, utopiapara.tex: + Add more stuff to utopia + +2001-02-18 Sunday 18:10 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: Makefile, diagram.mp, + hyp.tex, utopia.mp, utopiapara.tex: Start utopia image. Not very + utopistic yet... + +2001-02-18 Sunday 17:33 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Related-material + addition to the HTML section. + +2001-02-18 Sunday 17:01 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Hyphens to {} - don't + work + +2001-02-18 Sunday 16:59 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyperimg.txt: Added + description for the "real" picture. It is incomplet and probably + incorrekt. + +2001-02-18 Sunday 16:57 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Twid with + ref + +2001-02-18 Sunday 16:35 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: RFC talk + +2001-02-18 Sunday 16:29 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: rmcrud + +2001-02-18 Sunday 16:28 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small improvements + +2001-02-18 Sunday 16:24 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Edits + +2001-02-18 Sunday 16:19 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Twid + +2001-02-18 Sunday 16:13 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Bib fix, + Kata didn't want to go on + +2001-02-18 Sunday 16:04 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: LOTS of reorg and rm + crud. Getting there + +2001-02-18 Sunday 15:57 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move quote + +2001-02-18 Sunday 15:52 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Edit + +2001-02-18 Sunday 15:50 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Separate vr into its + own section --- possibly good + +2001-02-18 Sunday 15:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Add nakki + +2001-02-18 Sunday 15:42 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move figure + +2001-02-18 Sunday 15:40 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: Makefile, hyp.bib, hyp.tex: + Refer to XLink (IMPORTANT) + +2001-02-18 Sunday 15:20 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move markup again + +2001-02-18 Sunday 15:19 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: [no log message] + +2001-02-18 Sunday 14:31 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comment. + +2001-02-18 Sunday 14:29 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Oops. + +2001-02-18 Sunday 14:27 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Moved Vesa's figure + and added some text to SI: F+C. + +2001-02-18 Sunday 13:56 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: [no log message] + +2001-02-18 Sunday 13:52 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: rm crud2 + +2001-02-18 Sunday 13:51 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: rm crud + +2001-02-18 Sunday 13:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More + +2001-02-18 Sunday 13:45 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some changes. (Really + informational, isn't it?) + +2001-02-18 Sunday 13:44 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Oops + +2001-02-18 Sunday 13:43 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move markup section + +2001-02-18 Sunday 13:36 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Introon yksi kappale + - miettikaa + +2001-02-18 Sunday 13:33 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Nakki + + sect.nimi + oikea viite Coombsiin + +2001-02-18 Sunday 13:22 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Reword + +2001-02-18 Sunday 13:20 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove comment + +2001-02-18 Sunday 13:10 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Convert caption, more + float work + +2001-02-18 Sunday 11:49 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: [no log message] + +2001-02-18 Sunday 11:45 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Add a + rewritten version of Kimmo's thought. This could be the way to + explain our thinking... + +2001-02-18 Sunday 07:14 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: stuff + +2001-02-17 Saturday 22:44 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: Makefile, hyp.tex, hypf.tex: + Make it possible to simultaneously have both draft and non-draft + version (hypf). Fix a bit of wording, note some more oddities + +2001-02-17 Saturday 21:55 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Work on htmlification + +2001-02-17 Saturday 19:48 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove redundant + comments + +2001-02-17 Saturday 19:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Improve caption, + refer to figure in right place + +2001-02-17 Saturday 19:42 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comments bigger again + - there are less of them. Remove commented-out parts we will not be + using. + +2001-02-17 Saturday 18:33 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Replaced not-so-good + text with possibly bad text. + +2001-02-17 Saturday 18:09 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: /me puts the wiener + back on the table, uneaten. + +2001-02-17 Saturday 17:52 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Eating one of the + wieners + +2001-02-17 Saturday 17:47 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Finetune the BibTeX + database (accents & capitals, oh my) + +2001-02-17 Saturday 16:21 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Foo. + +2001-02-17 Saturday 16:03 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Nakki + +2001-02-17 Saturday 15:51 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Add Ted's + quote + +2001-02-17 Saturday 15:49 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: F+C stuff. + +2001-02-17 Saturday 15:30 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Kata's new abstract + +2001-02-17 Saturday 15:30 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Rearrangement. + +2001-02-17 Saturday 15:20 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: diagram.mp, hyp.tex: enlarge + font in diagrams + +2001-02-17 Saturday 15:08 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove references to + syntax descriptions, as we don't have time to do that properly + +2001-02-17 Saturday 15:02 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Title and comment + updates + +2001-02-17 Saturday 14:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove redundant + figure + +2001-02-17 Saturday 14:43 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More f+c work, it's + getting better. Also added a Q to Tuomas. + +2001-02-17 Saturday 14:39 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Improved floats. + +2001-02-17 Saturday 13:59 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: HTML-RFC-index.ps, hyp.tex: + Added paper frames to index pic. + +2001-02-17 Saturday 13:56 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some work on f+c, not + finished yet + +2001-02-17 Saturday 13:51 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More work on + htmlification. Now settling... + +2001-02-17 Saturday 13:41 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix final version + build. + +2001-02-17 Saturday 13:26 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/Makefile: Add PDF generation + (could work better with pdflatex but the images don't work with + it.) + +2001-02-17 Saturday 13:19 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Make figures flow in + non-draft version + +2001-02-17 Saturday 13:13 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: HTML-RFC-index.ps, hyp.tex: + Pic stuff. + +2001-02-17 Saturday 13:06 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Twid + +2001-02-17 Saturday 13:05 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: rm crud + +2001-02-17 Saturday 13:01 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More work on + htmlification + +2001-02-17 Saturday 12:55 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Change wiener + +2001-02-17 Saturday 12:54 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move figures, write + more about HTMLification + +2001-02-17 Saturday 12:30 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Fix figure + captions, add Kimmo's reference + +2001-02-17 Saturday 12:25 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fixed pic size. + +2001-02-17 Saturday 12:11 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move figures + +2001-02-17 Saturday 12:08 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Oops + +2001-02-17 Saturday 12:06 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: Makefile, hyp.tex: Add + Vesa's diagrams to the text. Needs work. + +2001-02-17 Saturday 12:02 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: Small + beginnings of a better htmlrfc section + +2001-02-17 Saturday 11:59 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: HTML-RFC.ps, demo1.css, + demo1.ps, demo2.css, demo2.ps, demo3.css, demo3.ps, demo4.css, + demo4.ps, hyp.tex: Added some pics. + +2001-02-17 Saturday 11:55 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/diagram.mp: added diarams + +2001-02-17 Saturday 11:43 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/Makefile: Add hyp.ps to + targets + +2001-02-17 Saturday 09:07 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Nakki... + +2001-02-17 Saturday 08:05 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: added a quick comment + +2001-02-16 Friday 20:35 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Make the comments + smaller and restore old title + +2001-02-16 Friday 16:36 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: comments + +2001-02-16 Friday 16:22 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comments. + +2001-02-16 Friday 15:58 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Commented out + \includegraphics, since the ps files aren't ready yet. + +2001-02-16 Friday 15:45 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: demo1.css, demo3.css, + hyp.tex, rfc1034.html: Comments. + +2001-02-16 Friday 15:41 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove old wiener + +2001-02-16 Friday 15:33 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comment on f+c + +2001-02-16 Friday 15:15 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove, as it doesn't + say anything useful. If we want, we can mention the xanadu + annotations etc. elsewhere + +2001-02-16 Friday 15:13 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Nakki Vesalle!!! + +2001-02-16 Friday 15:07 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Shaping up... + +2001-02-16 Friday 14:19 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Uusi nakki, + kommentteja + +2001-02-16 Friday 14:14 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Fix Ted's name. + +2001-02-16 Friday 14:13 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: focus and + context first attempt + +2001-02-16 Friday 14:07 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More work. Shaping + up. + +2001-02-16 Friday 13:55 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.tex, hyp.tex: More 2disp + work + +2001-02-16 Friday 13:52 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Add a wiener + +2001-02-16 Friday 13:42 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Added HTML spec. + +2001-02-16 Friday 13:25 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some more transfer + +2001-02-16 Friday 13:06 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More transfer... + +2001-02-16 Friday 12:59 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some work on transfer + +2001-02-16 Friday 12:36 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small twiddle in + transfer... + +2001-02-16 Friday 12:17 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Forgot to commit, + aargh (RFC index et al) + +2001-02-16 Friday 12:07 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Figures. + +2001-02-16 Friday 11:46 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Add ack + +2001-02-16 Friday 10:48 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small twiddle + +2001-02-16 Friday 10:43 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove obsolete + comments + +2001-02-16 Friday 10:41 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: move comments + +2001-02-16 Friday 10:03 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Start about + region-to-region links: it's a property of our current problem, the + RFCs. + +2001-02-16 Friday 10:01 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Heading + +2001-02-16 Friday 10:00 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Reorg + +2001-02-16 Friday 09:56 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Clarify stage + +2001-02-16 Friday 08:09 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Better addressing. + +2001-02-16 Friday 08:08 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comments & fixes. + +2001-02-16 Friday 07:50 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: A frankfurter done. + +2001-02-16 Friday 06:36 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Further fixing of + bibtex db + +2001-02-16 Friday 06:33 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: added + affiliation address + +2001-02-16 Friday 05:43 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: Comment on the RFCs + and fix the months. + +2001-02-15 Thursday 23:12 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: little + fixes + +2001-02-15 Thursday 22:48 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: lisätty + ranskalaisia nakkien seuraksi. + +2001-02-15 Thursday 22:06 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some more stuff. + PLEASE read and help fix the new section and structure + +2001-02-15 Thursday 21:51 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move trouble into + transfer section + +2001-02-15 Thursday 21:33 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move examples, start + editing problems section + +2001-02-15 Thursday 16:18 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More rearrangement + +2001-02-15 Thursday 16:10 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Another batch of + comments. + +2001-02-15 Thursday 16:07 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Ok + +2001-02-15 Thursday 16:06 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Rearrange a bit + +2001-02-15 Thursday 16:00 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comment. + +2001-02-15 Thursday 16:00 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Make non-draft really + work. Remove XXX ordering from authorname -- now it fits but only + barely. We have to order the authors later. Add new section. + +2001-02-15 Thursday 15:52 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comments & remove the + old thebibliography environment. + +2001-02-15 Thursday 15:21 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/: demo1.css, demo2.css, + demo3.css, demo4.css, rfc1034.html, rfcgen.sh: HTML f+c / non-f+c + stuff. + +2001-02-15 Thursday 14:58 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Clean up intro a + little bit + +2001-02-15 Thursday 14:57 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Make non-draft work + again. We're up to 5 pages without figures. Also, add clarifying + lines before sections in the source + +2001-02-15 Thursday 14:53 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fiddle with abstract + +2001-02-15 Thursday 14:44 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Oops... + +2001-02-15 Thursday 14:42 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: New abstract. I'm + beginning to feel really good about this: Finally we are getting to + our real MESSAGE. + +2001-02-15 Thursday 14:25 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Mods. + +2001-02-15 Thursday 14:16 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: bah + +2001-02-15 Thursday 14:02 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: demo1.css, hyp.tex, + rfc1034.html: Add css for the html demo + +2001-02-15 Thursday 13:34 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove the silly + notice + +2001-02-15 Thursday 13:33 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Add RCS id + +2001-02-15 Thursday 13:28 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Refer to hyperbolic + stuff for animation + +2001-02-15 Thursday 13:25 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small fix + +2001-02-15 Thursday 13:23 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: 1 nakki lisaa + +2001-02-15 Thursday 13:10 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: 1 nakki tehty + +2001-02-15 Thursday 12:49 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Nakkeja + +2001-02-15 Thursday 12:41 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/rfc1034.html: [no log message] + +2001-02-15 Thursday 12:39 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Nakki + +2001-02-15 Thursday 11:53 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: answer + +2001-02-15 Thursday 11:48 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Comment + +2001-02-15 Thursday 11:32 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.bib: fix a cite + +2001-02-15 Thursday 11:28 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: make better one rfc + para + +2001-02-15 Thursday 09:55 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Real hyperstructure + -> actual hyperstructure + +2001-02-15 Thursday 09:53 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix intuitivity + +2001-02-15 Thursday 09:45 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/Makefile: added a clean target + +2001-02-15 Thursday 09:38 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/Makefile: a makefile to + automate the processing + +2001-02-15 Thursday 09:33 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: jvk's comments + +2001-02-15 Thursday 06:57 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/: hyp.bib, hyp.tex: bibtexify + +2001-02-15 Thursday 05:45 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: a comment + +2001-02-14 Wednesday 21:53 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Add comments, edit a + little + +2001-02-14 Wednesday 19:59 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More. + +2001-02-14 Wednesday 19:57 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some small + improvements on the RFC section. + +2001-02-14 Wednesday 19:49 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: A fully rewritten RFC + intro section and couple of small nitpicks. + +2001-02-14 Wednesday 16:47 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Remove old comments + +2001-02-14 Wednesday 16:18 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix a typograpghic + mistake. + +2001-02-14 Wednesday 15:15 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Little + +2001-02-14 Wednesday 14:38 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move closer to + acm-required format + +2001-02-14 Wednesday 14:21 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Move co-operative + stuff + +2001-02-14 Wednesday 14:12 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: move a comment + +2001-02-14 Wednesday 14:11 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: A bit on the virutal + paper stuff + +2001-02-14 Wednesday 14:04 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Fix typo, rearrange + something, make possible to typeset in draft mode (with marginal + notes) and final mode. + +2001-02-14 Wednesday 13:59 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Reorg + +2001-02-14 Wednesday 13:56 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: my name & dept name + +2001-02-14 Wednesday 13:09 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small fixes + +2001-02-14 Wednesday 12:57 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small + +2001-02-14 Wednesday 12:37 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Foo. + +2001-02-14 Wednesday 12:03 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: cat->tjl + +2001-02-14 Wednesday 11:43 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Some answers. I'll + start modifying later. + +2001-02-14 Wednesday 09:50 Rauli Ruohonen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Blaa. + +2001-02-14 Wednesday 09:40 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: fix some typesetting + mistakes + +2001-02-14 Wednesday 08:53 Antti-Juhani Kaijanaho + + * Java/Main.java, Java/SpaceDump.java, Java/ZTPCommand.java, + Modules/ztp/client/Response.java, Modules/ztp/client/Session.java, + Modules/ztp/common/Command.java, + Modules/ztp/common/SubspaceDump.java, + Modules/ztp/server/Session.java: dump & slurp functionality + +2001-02-14 Wednesday 08:29 Katariina Ervasti + + * Documentation/Manuscripts/HyperRFC/hyp.tex: korjauksia + +2001-02-14 Wednesday 08:11 Antti-Juhani Kaijanaho + + * Documentation/Manuscripts/HyperRFC/hyp.tex: comments and typos + +2001-02-14 Wednesday 00:04 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: added a comment + +2001-02-13 Tuesday 22:59 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Answer most of Vesa's + comments. I jaksan't write any more tonight but tomorrow. Please + feel free to also contribute actual text ;) + +2001-02-13 Tuesday 21:54 Vesa Parkkinen + + * Documentation/Manuscripts/HyperRFC/hyp.tex: comments + +2001-02-13 Tuesday 19:55 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: foo + +2001-02-13 Tuesday 18:59 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More + +2001-02-13 Tuesday 18:54 Antti-Juhani Kaijanaho + + * Documentation/Spec/zzspec.wml: some cell ID stuff wrt space parts + and foreign cells + +2001-02-13 Tuesday 13:53 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More. PLEASE comment + +2001-02-13 Tuesday 11:01 Antti-Juhani Kaijanaho + + * Java/SpaceDump.java (gzigzag_conversion_2000_07_06): fix the dump + format + +2001-02-12 Monday 21:22 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: Small change + +2001-02-12 Monday 13:59 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: hyp.tex, hyp.tex, hyp.tex: + More + +2001-02-12 Monday 13:40 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/hyp.tex: More hyperrfc + +2001-02-12 Monday 13:30 Antti-Juhani Kaijanaho + + * Java/SpaceDump.java: file SpaceDump.java was initially added on + branch gzigzag_conversion_2000_07_06. + +2001-02-12 Monday 13:30 Antti-Juhani Kaijanaho + + * Java/ZZInvalidDimensionError.java: file + ZZInvalidDimensionError.java was initially added on branch + gzigzag_conversion_2000_07_06. + +2001-02-12 Monday 13:30 Antti-Juhani Kaijanaho + + * Java/: Main.java, SpaceDump.java, ZZDimSpace.java, + ZZInvalidDimensionError.java, ZZSpace.java, storage/DirSet.java, + storage/Recs.java, storage/Recs.pl, storage/WritableHash.java, + storage/WritableSet.java, storage/ZZPersistentDimSpace.java, + storage/ZZPersistentDimension.java (gzigzag_conversion_2000_07_06): + add space dump functionality for conversion purposes + +2001-02-12 Monday 12:50 Tuomas J. Lukka + + * Documentation/Manuscripts/HyperRFC/: ht01e.sty, hyp.tex: foo + +2001-02-09 Friday 08:30 Antti-Juhani Kaijanaho + + * Java/media/StringScroll.java: some documentation + +2001-02-09 Friday 06:05 Antti-Juhani Kaijanaho + + * Documentation/Networking/: ZTP-usage.txt, ZTP-usage.txt: document + more + +2001-02-09 Friday 06:00 Antti-Juhani Kaijanaho + + * Java/ZZEmergencyCommandLineInterface.java: oops + +2001-02-09 Friday 05:59 Antti-Juhani Kaijanaho + + * Documentation/FAQ, Java/ZZEmergencyCommandLineInterface.java: + refer to the new bug reporting page + +2001-02-08 Thursday 11:31 Antti-Juhani Kaijanaho + + * Modules/ztp/client/Session.java: fix a bug + +2001-02-08 Thursday 11:18 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-ZTPTCP.txt, Java/ZZCell.java, + Java/ZZDimSpace.java, Java/ZZSpace.java, + Java/storage/ZZCacheDimSpace.java, Modules/ztp/client/Get.java, + Modules/ztp/client/Session.java, + Modules/ztp/common/SubspaceDump.java, + Modules/ztp/server/PutMessage.java: more ZTP work; now GET works + even in client + +2001-02-08 Thursday 08:19 Antti-Juhani Kaijanaho + + * Modules/ztp/: client/Get.java, client/Put.java, + client/Subspace.java, common/SubspaceDumper.java, + server/PutMessage.java, client/Session.java, + common/SubspaceDump.java, common/SubspaceDumper.java, + server/GetMessage.java, server/PutMessage.java: more ZTP work + +2001-02-08 Thursday 05:51 Antti-Juhani Kaijanaho + + * Java/: SysLogger.java, arch/syslog/arch.mk: more gnu->syslog + + making the arch.mk better + +2001-02-08 Thursday 05:42 Antti-Juhani Kaijanaho + + * Documentation/Networking/ZTP-usage.txt: gnu->syslog + +2001-02-08 Thursday 05:41 Antti-Juhani Kaijanaho + + * Java/arch/syslog/: arch.mk, org_gzigzag_SysLogger.c: another + move, hope this one is final (it's not gnu either:-) + +2001-02-07 Wednesday 14:24 Antti-Juhani Kaijanaho + + * Modules/ztp/: client/.cvsignore, server/.cvsignore: some ignores + +2001-02-07 Wednesday 14:23 Antti-Juhani Kaijanaho + + * Documentation/Networking/ZTP-usage.txt: added brief ZTP usage + instructions + +2001-02-07 Wednesday 14:02 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-ZTPTCP.txt, Java/SafeExit.java, + Java/ZZCell.java, Modules/ztp/ZTPclient.java, + Modules/ztp/client/Action.java, Modules/ztp/client/Get.java, + Modules/ztp/client/Put.java, + Modules/ztp/client/RemotePieceData.zob, + Modules/ztp/client/Response.java, Modules/ztp/client/Session.java, + Modules/ztp/common/Command.java, + Modules/ztp/common/LineBufferedIO.java, + Modules/ztp/common/SubspaceDumper.java, + Modules/ztp/server/GetMessage.java, + Modules/ztp/server/PutMessage.java: "first partially working + client: it can put! + +2001-02-07 Wednesday 10:39 Antti-Juhani Kaijanaho + + * Modules/ztp/common/Command.java: document + +2001-02-07 Wednesday 10:35 Antti-Juhani Kaijanaho + + * Modules/ztp/: common/Command.java, server/Command.java, + common/Command.java: Command is used by both client and server + +2001-02-07 Wednesday 10:32 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-ZTPTCP.txt, + Modules/ztp/ZTPclient.java, Modules/ztp/server/Session.java: some + more work on ZTP client + +2001-02-07 Wednesday 10:29 Katariina Ervasti + + * Documentation/UsersGuide/newug.wml: documentation again + +2001-02-07 Wednesday 10:19 Katariina Ervasti + + * Documentation/UsersGuide/newug.wml: cat also forgot something + else of the user's guide + +2001-02-07 Wednesday 10:14 Katariina Ervasti + + * Documentation/UsersGuide/: active.png, aftermove.png, + newcells.png, newstory.png, newstory2.png, newstory3.png, + rastererror.png, start.png, story.png, storytext.png: uups cat + forgot to add the images + +2001-02-07 Wednesday 10:11 Katariina Ervasti + + * Documentation/UsersGuide/newug.wml: # cat finally updates the + user's guide + +2001-02-07 Wednesday 08:21 Antti-Juhani Kaijanaho + + * Modules/ztp/server/: GetMessage.java, PutMessage.java: added some + synchronization + +2001-02-07 Wednesday 07:38 Antti-Juhani Kaijanaho + + * Modules/ztp/server/: GetMessage.java, Session.java: a very + primitive ZTP GET works now for the whole space + +2001-02-07 Wednesday 07:12 Antti-Juhani Kaijanaho + + * Modules/ztp/server/Command.java: fix bug in encode + +2001-02-07 Wednesday 06:01 Antti-Juhani Kaijanaho + + * Modules/ztp/server/Command.java: better style for ASCII_word_char + +2001-02-06 Tuesday 12:12 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-ZTPTCP.txt, + Documentation/Networking/ztp.wml, Modules/ztp/server/Command.java, + Modules/ztp/server/GetMessage.java, + Modules/ztp/server/PutMessage.java: more ZTP work + +2001-02-06 Tuesday 07:47 Antti-Juhani Kaijanaho + + * Modules/ztp/server/: Command.java, PutMessage.java: oops + +2001-02-06 Tuesday 07:35 Antti-Juhani Kaijanaho + + * Modules/ztp/: ZTPserver.java, common/LineBufferedIO.java, + server/Listener.java, server/Session.java, server/UserManager.java, + server/UserRecord.zob: move around ZTP classes into a more refined + package structure + +2001-02-06 Tuesday 07:11 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-ZTPTCP.txt, + Modules/ztp/server/Session.java: ztp put works for the whole space + now + +2001-02-05 Monday 13:25 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-ZTPTCP.txt, + Modules/ztp/server/Session.java: today's work on ztp + +2001-02-05 Monday 11:47 Antti-Juhani Kaijanaho + + * Java/Makefile, Modules/ztp/server/Listener.java: more ztp work + +2001-02-05 Monday 11:38 Antti-Juhani Kaijanaho + + * Java/SysLogger.java: hmm, it's not posix, so it's better off + being gnu + +2001-02-05 Monday 11:26 Antti-Juhani Kaijanaho + + * Java/Main.java, Java/Makefile, Java/SysLogger.java, + Java/ZZLogger.java, Modules/ztp/ZTPserver.java, + Modules/ztp/server/Session.java, + Modules/ztp/server/UserManager.java: more work on ZTP server + +2001-02-05 Monday 08:31 Antti-Juhani Kaijanaho + + * Java/Main.java, Modules/ztp/ZTPserver.java: now works from Main + too:-) + +2001-02-05 Monday 08:09 Antti-Juhani Kaijanaho + + * Documentation/Networking/: ZTP.txt, ztp.wml: more STP->ZTP + +2001-02-05 Monday 08:04 Antti-Juhani Kaijanaho + + * Documentation/Networking/Makefile, + Documentation/Networking/STP.txt, Documentation/Networking/ZTP.txt, + Documentation/Networking/mock-STPTCP.txt, + Documentation/Networking/mock-ZTPTCP.txt, + Documentation/Networking/stp.wml, Documentation/Networking/ztp.wml, + Java/Main.java, Java/Makefile, Modules/ztp/ZTPserver.java, + Modules/ztp/server/Listener.java, Modules/ztp/server/Session.java, + Modules/ztp/server/UserManager.java, + Modules/ztp/server/UserRecord.zob, + Modules/ztp/common/LineBufferedIO.java: file renames to move stp -> + ztp + +2001-02-05 Monday 07:40 Antti-Juhani Kaijanaho + + * Documentation/Networking/mock-STPTCP.txt, Java/Makefile: first + working version, no real functionality yet + +2001-02-05 Monday 06:11 Antti-Juhani Kaijanaho + + * Java/Makefile: scan stp subdirectories for zobs + +2001-02-02 Friday 12:32 Antti-Juhani Kaijanaho + + * Documentation/Networking/Makefile: oops, forgot this one + +2001-01-26 Friday 13:53 Antti-Juhani Kaijanaho + + * NEWS, Java/Makefile, Java/ZZKeyBindings1.java, + Java/flob/RowColView.zob, Java/media/FText.java, + Java/media/FirstMatchBreaker.java, + Java/storage/ZZPersistentDimension.java, Modules/nile/Nile1.java, + Modules/nile/Nile1View.zob, Modules/nile/Nile2Ops.java: merge from + 0.5 + +2001-01-26 Friday 13:47 Antti-Juhani Kaijanaho + + * Java/: Makefile, media/UTF8Char.java: a currently useless + framework for a mock-STP/TCP server + +2001-01-25 Thursday 12:46 Rauli Ruohonen + + * Java/Main.java: PDA mode: Added flag '-pda'. + +2001-01-25 Thursday 10:09 Rauli Ruohonen + + * Java/storage/: ZZPersistentDimension.java (ver_0_5), + ZZPersistentDimension.java: Fixed a trigger bug. + +2001-01-24 Wednesday 17:10 Benjamin Fallenstein + + * Java/flob/RowColView.zob (ver_0_5): Show the dimensions in + RowColView + +2001-01-24 Wednesday 17:02 Benjamin Fallenstein + + * Modules/nile/: Nile1.java, Nile2Ops.java (ver_0_5): More Nile + fixes + +2001-01-24 Wednesday 17:00 Benjamin Fallenstein + + * Java/ZZKeyBindings1.java (ver_0_5): A new kind of binding, + INSERT, which is tried immediately before DEFAULT, if the action + was a single-character key press (used in Nile to change the mode + to character mode only if we will actually insert something, and + probably useful in all applitude tools which allow entering text) + +2001-01-24 Wednesday 14:05 Benjamin Fallenstein + + * Modules/nile/: Nile1.java, Nile1View.zob, Nile2Ops.java + (ver_0_5): Nile fixes + +2001-01-24 Wednesday 11:05 Benjamin Fallenstein + + * Java/media/FirstMatchBreaker.java (ver_0_5): oops, forgot to add + +2001-01-24 Wednesday 11:05 Benjamin Fallenstein + + * Java/media/FirstMatchBreaker.java: file FirstMatchBreaker.java + was initially added on branch ver_0_5. + +2001-01-24 Wednesday 11:03 Benjamin Fallenstein + + * Java/media/FText.java (ver_0_5): A new linebreaker -- not the TeX + one, but another trivial first-fit one. Works perfectly (as far as + I have tested it), is faster, and does multiline + +2001-01-24 Wednesday 08:32 Vesa Parkkinen + + * Java/ZZDimension.java: fixed a null pointer in hop + +2001-01-22 Monday 08:37 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_5): Fix MODULES. + +2001-01-20 Saturday 08:56 Benjamin Fallenstein + + * Modules/vob/: Connection.java, View.java, Vob.java, VobSet.java, + VobStore.java: Vob draft, based on what Vesa and I figured out + yesterday -- VobSets are pseudo-hierarchical, coordinates + conceptually belong into VobSets, connections are between vobs + (does not compile yet) + +2001-01-20 Saturday 08:52 Benjamin Fallenstein + + * Modules/panes/: .cvsignore, PaneView.zob: First draft of paned + view + +2001-01-19 Friday 11:19 Tero Mäyränen + + * Modules/multimedia/: Default.java, MediaFlobFactory.java, + MediaZOb.java, flobcolors.java, image.java, next.java, rect.java, + text.java: This version attempts to cache the MediaZObs.. + +2001-01-18 Thursday 10:06 Antti-Juhani Kaijanaho + + * Documentation/Networking/: STP.txt, stp.wml: work-in-progress + versions of STP docs + +2001-01-18 Thursday 07:59 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_5): sync JARMODULES with MODULES + +2001-01-18 Thursday 07:47 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_5): add another build iteration to jar + target + +2001-01-18 Thursday 07:39 Antti-Juhani Kaijanaho + + * Java/Makefile (ver_0_5): enable vc and mm modules + +2001-01-18 Thursday 07:34 Antti-Juhani Kaijanaho + + * NEWS (ver_0_5): 0.5 preparation + +2001-01-17 Wednesday 14:27 Tuomas J. Lukka + + * Modules/servlet/: VCServlet.java, ZZServlet.java, startjetty, + zzserv.prp, zzserv2.prp: Servlets... + +2001-01-17 Wednesday 14:23 Tuomas J. Lukka + + * Java/: ZZCell.java, ZZCellHandle.java: Hopefully fix cells in + hashtables as keys + +2001-01-17 Wednesday 12:46 Benjamin Fallenstein + + * Java/flob/CellFlobFactory2.zob: A new version of CellView 2, + finally able to do multiline (but not bug-free) + +2001-01-17 Wednesday 10:50 Rauli Ruohonen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, + VirtualCommunity.zob, VirtualCommunity.zob: [no log message] + +2001-01-17 Wednesday 10:20 Rauli Ruohonen + + * Java/flob/FTextLayouter.zob, + Modules/virtualcommunity/MessageFlobFactory.zob: [no log message] + +2001-01-17 Wednesday 10:13 Benjamin Fallenstein + + * Java/flob/FTextLayouter.zob: Fix + +2001-01-17 Wednesday 10:12 Rauli Ruohonen + + * Java/media/FText.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VirtualCommunity.zob: Foo + +2001-01-17 Wednesday 09:24 Antti-Juhani Kaijanaho + + * Modules/virtualcommunity/VirtualCommunity.zob: fixed copyright + year + +2001-01-17 Wednesday 08:56 Rauli Ruohonen + + * Java/media/FText.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VirtualCommunity.zob: Blaa. + +2001-01-17 Wednesday 08:03 Antti-Juhani Kaijanaho + + * Java/ZZViewComponent.java: a really bad quick hack to make a + ring, a diaeresis and o diaeresis work + +2001-01-17 Wednesday 05:43 Vesa Parkkinen + + * Modules/virtualcommunity/VirtualCommunity.zob: more vc demo stuff + +2001-01-17 Wednesday 03:04 Vesa Parkkinen + + * Java/flob/CellBgFlob.java: added a method to set the background + color + +2001-01-17 Wednesday 03:00 Vesa Parkkinen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, + VirtualCommunity.zob: more work on the vc demo + +2001-01-16 Tuesday 16:18 Rauli Ruohonen + + * Java/ZZPrimitiveActions.java, Java/flob/CellFlobFactory1.zob, + Java/flob/FTextLayouter.zob, Java/media/FText.java, + Modules/multimedia/MediaFlobFactory.java, + Modules/virtualcommunity/MessageFlobFactory.zob, + Modules/virtualcommunity/VirtualCommunity.zob: Bugfixes. + +2001-01-16 Tuesday 14:09 Rauli Ruohonen + + * Java/flob/Flob.java, Modules/multimedia/MediaFlobFactory.java, + Modules/virtualcommunity/MessageFlobFactory.zob: Some bugfixes. + +2001-01-16 Tuesday 12:58 Vesa Parkkinen + + * Java/flob/FTextLayouter.zob: quick fix to get virtualcommunity + demo working + +2001-01-16 Tuesday 11:40 Vesa Parkkinen + + * Modules/multimedia/: ImageSource.java, MediaFlobFactory.java: + fixed few non-1.1 methods + +2001-01-16 Tuesday 10:12 Vesa Parkkinen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, + VirtualCommunity.zob: more code to the demo + +2001-01-16 Tuesday 09:57 Tero Mäyränen + + * Modules/multimedia/: MediaFlobFactory.java, MediaZOb.java, + image.java: Small update, shows image by just writing an URL to a + cell when mm.MediaFlobFactory is in use... + +2001-01-16 Tuesday 02:39 Rauli Ruohonen + + * Modules/virtualcommunity/: MessageFlobFactory.zob, + VirtualCommunity.zob: Some code for the demo. + +2001-01-15 Monday 18:25 Vesa Parkkinen + + * Modules/virtualcommunity/VirtualCommunity.zob: added + virtualcommunity module + +2001-01-15 Monday 13:07 Tero Mäyränen + + * Modules/multimedia/: Default.java, ImageSource.java, + MediaFlobFactory.java, MediaZOb.java, flobcolors.java, image.java, + mm.java, next.java, rect.java, text.java: Preliminary version of + the multimedia module primarily just for the upcoming demo. + +2001-01-12 Friday 12:55 Antti-Juhani Kaijanaho + + * Java/ZZDefaultSpace.java: Add cursor view to AllViews + +2001-01-07 Sunday 18:59 Benjamin Fallenstein + + * Modules/nile/draft/: Nile3Ops.java, Nile3Part.java, + Nile3Pos.java, Nile3Unit.java: A very preliminary version of a + possible 3rd generation Nile API + +2001-01-07 Sunday 18:21 Benjamin Fallenstein + + * Java/clang/Data.java, Modules/zaubertrank/Evaluator.java, + Modules/zaubertrank/ZaubertrankPart.java: More work on the + zaubertrank + +2001-01-06 Saturday 21:32 Benjamin Fallenstein + + * Modules/notemap/Notemap.zob: Now supporting directed links. + Selecting certain link types is needed next. + +2001-01-05 Friday 12:33 Antti-Juhani Kaijanaho + + * NEWS, changelog-authors, Documentation/Makefile, + Documentation/index.html, Documentation/Nile/Makefile: merge from + 0.4 + +2001-01-04 Thursday 14:07 Benjamin Fallenstein + + * Modules/notemap/.cvsignore: cvsignore + +2001-01-04 Thursday 14:06 Benjamin Fallenstein + + * Java/ZZCursorReal.java, Java/clang/Data.java, + Modules/zaubertrank/Actions.java, + Modules/zaubertrank/Evaluator.java, + Modules/zaubertrank/Primitive.java, + Modules/zaubertrank/PrimitiveSet.java: Some more work on the + zaubertrank, ZZCursorReal.adjustCursors for use after insertions or + deletions in cells + +2001-01-03 Wednesday 16:47 Rauli Ruohonen + + * Java/Main.java, Java/ZZCanvasView.java, Java/ZZDefaultSpace.java, + Java/ZZObsTrigger.java, Java/ZZPrimitiveActions.java, + Java/ZZViewComponent.java, Java/ZZWindows.java, + Modules/applet/ZZApplet.java, Modules/nile/NileApplet.java: Added + ZZ structure observation in ZZWindows, enable/disable and + chg(ZZObs) to ZZObsTrigger, fixed some bugs and moved most of the + windowing stuff from the applets to ZZWindows. + +2001-01-02 Tuesday 11:53 Rauli Ruohonen + + * Java/: Main.java, ZZCanvasView.java, ZZCell.java, + ZZObsTrigger.java, ZZUpdateManager.java, ZZUtil.java, + ZZViewComponent.java, ZZWindows.java, + storage/ZZCacheDimension.java: Triggering bugfixes and some changes + in behavior. + diff --git a/ChangeLog.2000 b/ChangeLog.2000 new file mode 100644 index 0000000..7f6ea31 --- /dev/null +++ b/ChangeLog.2000 @@ -0,0 +1,1329 @@ +2000-12-31 Sunday 15:23 Benjamin Fallenstein + + * Java/flob/CursorView.zob: Fix + +2000-12-31 Sunday 15:15 Benjamin Fallenstein + + * Java/: ApplitudeMgr.java, ZZDefaultSpace.java, + ZZKeyBindings1.java, ZZPrimitiveActions.java, + flob/CombinedView.zob: Fixes + +2000-12-31 Sunday 15:12 Benjamin Fallenstein + + * Java/flob/FlobSet.java: Make FlobSet MUCH more efficient, not + using Vectors when not needed + +2000-12-29 Friday 00:01 Benjamin Fallenstein + + * Java/Makefile: Add notemap + +2000-12-28 Thursday 22:46 Benjamin Fallenstein + + * Java/flob/MultiView.zob: Improve applitude interconnectivity + +2000-12-28 Thursday 02:18 Benjamin Fallenstein + + * Java/flob/.cvsignore: ...and now: an attempt at THE REAL THING + (applitude interconnectivity) + +2000-12-28 Thursday 01:19 Benjamin Fallenstein + + * Modules/nile/NileDemo.java: Now applitude bindings work quite + well, including mode changes -- i.e., Nile works together with + other applitudes + +2000-12-27 Wednesday 21:11 Benjamin Fallenstein + + * Java/flob/Flob.java: Now able to change applitude by clicking + +2000-12-27 Wednesday 12:14 Benjamin Fallenstein + + * Modules/notemap/Notemap.zob: Half-fix: it isn't *right*, but + readable now even in special cases + +2000-12-27 Wednesday 12:11 Antti-Juhani Kaijanaho + + * Documentation/Math/ajk-scribbles.tex: Initial revision. + +2000-12-27 Wednesday 00:43 Benjamin Fallenstein + + * NEWS: Update + +2000-12-26 Tuesday 22:48 Benjamin Fallenstein + + * Java/storage/MemWritable.java, Modules/nile/NileApplet.java: OK, + make it actually work + +2000-12-26 Tuesday 21:59 Benjamin Fallenstein + + * Modules/nile/SplitNileDemo.java: Draft of an applet demoing split + nile (actually, it works, except StringScroll needs a writable -- + which disables scrolls/spans -- which disables transclusions, which + basicly is the coolest thing we want to show...) + +2000-12-26 Tuesday 21:13 Benjamin Fallenstein + + * Modules/nile/.cvsignore: Add SplitNileView + +2000-12-26 Tuesday 21:12 Benjamin Fallenstein + + * Modules/nile/Nile1.java: Fix a bit + +2000-12-26 Tuesday 20:15 Benjamin Fallenstein + + * Modules/nile/SplitNileView.zob: Forgot to add, again... + +2000-12-26 Tuesday 20:15 Benjamin Fallenstein + + * Java/flob/CoordDecor.java: WOW: Parallel Nile streams -- showing + transclusions with beams + +2000-12-26 Tuesday 15:20 Benjamin Fallenstein + + * Java/flob/SplitView.zob: Oops, forgot to add... + +2000-12-26 Tuesday 15:20 Benjamin Fallenstein + + * Java/flob/Renderable.java: Put in hooks for the basic capability + of combining views, and a funny view that uses them + +2000-12-26 Tuesday 14:09 Benjamin Fallenstein + + * Java/media/FText.java: Fix capitalisation + +2000-12-25 Monday 19:55 Benjamin Fallenstein + + * Modules/nile/Nile2Ops.java: ...and, forgot to commit this + +2000-12-25 Monday 19:37 Benjamin Fallenstein + + * Java/: flob/FTextLayouter.zob, media/Capitalizer.java: Abstract + string capitalization out to a Capitalizer class, change FText and + FTextLayouter API (next step would be to move firstCap out of + FTextLayouter -- it does NOT belong there! -- and into the views; + at the same time, get rid of the calls with beginningSentence[]. + Too much work to do it now) + +2000-12-25 Monday 17:26 Benjamin Fallenstein + + * Java/clang/: Data.java, flowing/Data.java: Make Data usable by + all clangs also, doc a bit (I moved it to org.gzigzag because that + causes the least changes, but it'd be better to move it to + org.gzigzag.clang someday.) + +2000-12-25 Monday 13:58 Benjamin Fallenstein + + * Modules/zaubertrank/ZaubertrankPart.java, + Java/storage/ZZCacheDimSpace.java: A spacepart for the zaubertrank, + with a dimension that shows the elements of a zaubertrank token + tree in Reverse Polish Notation. + +2000-12-25 Monday 13:54 Benjamin Fallenstein + + * Java/errors/: MissingTermError.java, SyntaxError.java: Oops, + publicize + +2000-12-25 Monday 12:22 Benjamin Fallenstein + + * Java/clang/thales/SyntaxError.java: Move SyntaxError to + org.gzigzag and Java/errors -- I think it should be possible for + all clangs to use the same SyntaxError exception. If we want to + separate, we can have subclasses. + +2000-12-25 Monday 09:45 Benjamin Fallenstein + + * changelog-authors: Last time commits weren't mailed through + gzz-commits, not everyone was on changelog-authors, so try adding + everyone on the SourceForge Project Member List ;) (it can't hurt, + can it now?) + +2000-12-24 Sunday 21:24 Benjamin Fallenstein + + * Java/transform/Convert.java: A handy little utility to convert + from old to new file format + +2000-12-24 Sunday 13:54 Benjamin Fallenstein + + * Java/: Dump.java, dump2java.pl: More work on dumping + +2000-12-22 Friday 22:44 Benjamin Fallenstein + + * Java/Dumper.java: Make im- and export of dumps work; dump2java + converter later to be invoked on compiletime, to make a Java file + which recreates the dumped subspace + +2000-12-20 Wednesday 22:26 Benjamin Fallenstein + + * Modules/nile/Nile2Iter.java: Jump between nile transclusions -- + unfortunately, this *does* cheat + +2000-12-18 Monday 19:24 Benjamin Fallenstein + + * Java/: Main.java, ZZDimSpace.java, ZZSpace.java: Put the hooks in + to find all cells whose spans overlap a given span. New arg for + Main, -span, so that normal users won't be slowed down until we + have a reasonable implementation for SpanSet. + +2000-12-17 Sunday 17:24 Benjamin Fallenstein + + * Modules/nile/Nile1View.zob: Turn standard debug off + +2000-12-17 Sunday 16:32 Benjamin Fallenstein + + * Modules/nile/Nile2Unit.java: Nile transclusions + +2000-12-12 Tuesday 18:43 Tuomas J. Lukka + + * Java/storage/ZZPersistentDimSpace.java: + PersistentDimSpace.recreateMasterDimList must set the space of the + dimension or there'll be problems. + +2000-12-12 Tuesday 11:18 Antti-Juhani Kaijanaho + + * Java/storage/ZZPersistentDimension.java: s/final// for dbg, also + enable one commented-out p() + +2000-12-11 Monday 21:38 Tuomas J. Lukka + + * Java/media/TestLines.java: Change method use deprecated in jdk1.3 + +2000-12-11 Monday 19:47 Tuomas J. Lukka + + * Java/ScalableFont.java: Clean up, restyle, document + +2000-12-11 Monday 13:57 Antti-Juhani Kaijanaho + + * Documentation/Nile/Makefile (ver_0_4): Fix^2: Nile in 0.4 doc + tarball + +2000-12-11 Monday 13:40 Antti-Juhani Kaijanaho + + * Documentation/Makefile (ver_0_4): Nile in 0.4 doc tarball + +2000-12-11 Monday 13:20 Antti-Juhani Kaijanaho + + * Documentation/index.html (ver_0_4): Nile docs + +2000-12-11 Monday 09:20 Rauli Ruohonen + + * Java/ZZUpdateManager.java, Modules/applet/ZZApplet.java, + Modules/prez/PrezRaster.zob: Cleaned ZZUpdateManager up a bit + (clarified comments, removed unused variables). Fixed a null + pointer reference bug in PrezRaster. Modified ZZApplet so that it + works again. + +2000-12-11 Monday 09:03 Rauli Ruohonen + + * Java/ZOb.java, Java/ZZCommand.java, Java/ZZWindows.java, + Java/zob2java.pl, Java/flob/CellFlobFactory1.zob, + Java/flob/CellFlobFactory2.zob, + Java/flob/IdiosyncraticFlobFactory.zob, + Java/flob/ParallelTextView.zob, Java/flob/RankTextView.zob, + Modules/textcloud/TextCloud.zob: Replaced ad hoc font scaling stuff + in zobs with use of ScalableFont. Nile is the only view still using + the old way. + +2000-12-11 Monday 02:54 Tuomas J. Lukka + + * Java/flob/VanishingView.zob: Add more efficient getPoint to Flob, + document FlobSet little + +2000-12-11 Monday 02:54 Tuomas J. Lukka + + * Java/flob/VobSet.java: Start drafting new API + +2000-12-10 Sunday 21:18 Benjamin Fallenstein + + * Java/flob/SimpleTextView.zob: Make editview work with + SimpleTextView, new HELP command bound to F1 + +2000-12-10 Sunday 17:14 Tuomas J. Lukka + + * Modules/nile/Nile1.zob: Reorganize a bit + +2000-12-09 Saturday 02:29 Tuomas J. Lukka + + * Documentation/Nile/nileug.wml: Short nile user's guide + +2000-12-08 Friday 23:05 Tuomas J. Lukka + + * Documentation/Nile/nile.wml, Java/ZZCursorReal.java: Nile now + basically works as a text editor. Now it's time to start testing it + out and fixing the details. Whew! + +2000-12-08 Friday 12:50 Benjamin Fallenstein + + * Modules/zaubertrank/: Actions.java, ParsedView.zob, Parser.java, + Zaubertrank.java: Yet some more work on the zaubertrank + +2000-12-07 Thursday 00:37 Tuomas J. Lukka + + * Modules/nile/: Nile1Ops.java, Nile1Text.java, Nile2Test.java: + More nile work. Now moved to new APIs, which make things a LOT + simpler than the earlier ones. The way the word-breaking code works + is almost clear now ;). Sentences and paragraphs untested. Should + define actions soon. + +2000-12-07 Thursday 00:36 Tuomas J. Lukka + + * Java/ZZCell.java: Add new method: findCell to look for a cell + along a rank. + +2000-12-06 Wednesday 10:36 Benjamin Fallenstein + + * Modules/zaubertrank/SimpleView.zob: More work on the zaubertrank + +2000-12-05 Tuesday 03:44 Tuomas J. Lukka + + * Java/mungencss.pl: A small script to remove generated routines + from the javancss output. + +2000-12-05 Tuesday 03:43 Tuomas J. Lukka + + * Java/clang/heraclitus/: HeraclitusClang.java, + HeraclitusCommand.zob, Primitive.java: Comment some more, change + cursorparam to param. + +2000-12-05 Tuesday 02:01 Tuomas J. Lukka + + * Documentation/wmlinc/art.css: More nile doc + +2000-12-04 Monday 22:11 Benjamin Fallenstein + + * Modules/zaubertrank/: .cvsignore, README.html, TokenFlob.java, + TokenGrouper.java: More work on the zaubertrank + +2000-12-04 Monday 13:01 Tuomas J. Lukka + + * Java/: JEv.java, ZZViewComponent.java, media/Stream.java: Clean + up some old code + +2000-11-30 Thursday 19:44 Tuomas J. Lukka + + * Java/flob/SplitCellFlob1.java: SplitCellFlobs MUST have the same + cell if they are parent and nextPart. + +2000-11-30 Thursday 19:43 Tuomas J. Lukka + + * Java/ZZUtil.java: Make mix a little more careful + +2000-11-30 Thursday 08:44 Antti-Juhani Kaijanaho + + * Makefile, manifest-filter.pl, Java/ZZDimension.java, + Java/ZZLocalDimension.java, Java/storage/ZZCacheDimension.java, + Modules/test/TestUndo.java: merge from 0.3 + +2000-11-28 Tuesday 12:07 Antti-Juhani Kaijanaho + + * Java/media/StringScroll.java: Update author info. + +2000-11-27 Monday 11:09 Antti-Juhani Kaijanaho + + * Java/media/UTF8Char.java: New UTF-8 StringScroll format + +2000-11-25 Saturday 00:36 Tuomas J. Lukka + + * Java/: ZZCursor.java, ZZCursorVirtual.java: Nile now knows how to + select single words when clicked by mouse. Hopping them over each + other is the next task... + +2000-11-24 Friday 16:24 Tuomas J. Lukka + + * Java/media/VStream.java: Further nile work - now showing the + selected unit should just about work, then for making the actual + units. This nastily complicates the view code but that's life - it + shouldn't be getting much worse after this, anyway. + +2000-11-24 Friday 03:02 Tuomas J. Lukka + + * Modules/nile/README: More nile work. Factor out vstream cursor + move from PrimitiveActions - this should probably be done for a + number of other actions, too... + +2000-11-22 Wednesday 17:19 Antti-Juhani Kaijanaho + + * Documentation/: CyberText/permascroll.png, + CyberText/rank1vert.png, CyberText/rank2vert.png, + CyberText/rank3both.png, Spec/canvasraster.png, Spec/cursor1.png, + Spec/cursordim.png, Spec/inheritparam.png, Spec/rasterspec.png: + generated files OUT! + +2000-11-22 Wednesday 00:35 Tuomas J. Lukka + + * Modules/nile/Nile1GenTreeModel.java: Various changes to make nile + have its own window and modes. Now we can start working on the ops + in peace, and because it's bound to a real window, we can very + easily see what is happening in the structure. Of course, this is + not how it will be in the end: in the end it will be just one of + the views and views can also have states but for now, we'll do + this. + +2000-11-20 Monday 17:36 Tuomas J. Lukka + + * Modules/nile/Nile1Div.java: More nile work + +2000-11-20 Monday 12:59 Tuomas J. Lukka + + * Java/flob/FlobView.java: Fix rcsid + +2000-11-19 Sunday 01:49 Tuomas J. Lukka + + * Modules/hypergenealogy/HyperGenealogy.zob: More work - now can + show each time step, so can basically animate. + +2000-11-17 Friday 18:46 Tuomas J. Lukka + + * Java/flob/FTextLayouter.java: Add firstcap and + section-title-jumping to nile. It is starting to look pretty good. + Text entry is still difficult because you have to make the tags by + hand but that'll get easier soon. The problem with fistcap is that + it's done completely wrong now and needs to be redone. 1: there + should be a central place to do it, with its own state object, 2: + there should be less awareness of it throughout classes, it should + be a single call to FText, not involving FTextLayout at all, 3: it + should be thought out whether we do really want it to e at this + level or whether we should explicitly store sentence breaks in nile + - I don't know yet. But entering the sentence break by two spaces + feels quite natural (that's Ted's design). + +2000-11-17 Friday 13:52 Antti-Juhani Kaijanaho + + * Documentation/UsersGuide/: addressbook.png, alku.png, bind1.png, + bind2.png, boring.png, breakkafka.png, change1.png, change2.png, + child1.png, child2.png, connection1.png, creation.png, + dimensio.png, extra.png, f2.png, familytree.png, font.png, + grey.png, hop1.png, hop2.png, hopolympos.png, htree.png, kafka.png, + klooni.png, make1.png, make2.png, make3.png, make4.png, make5.png, + make6.png, margins.png, mark1.png, mark2.png, markconnect.png, + mutsi.png, mutsiosoite.png, myspeech.png, myspeech1.png, + myspeech2.png, myspeech3.png, newug.wml, olympos.png, olympos2.png, + osoite.png, para.png, rainy.png, rcfact1.png, rotate.png, row.png, + shiny.png, shinyhappy.png, shinyhappy2.png, shinyhappy3.png, + structure1.png, structure2.png, suku.png, testi.png, + wallstreet.png, widthstr.png, wrongconn.png (ver_0_2): bring + current manual from trunk to frozen branch + +2000-11-16 Thursday 21:01 Tuomas J. Lukka + + * Java/part/GenTreePart.java: Make space upgrade work again. Put + the old system list in a reasonable place. Remove dcold since it + doesn't mean anything after that. + +2000-11-16 Thursday 20:33 Benjamin Fallenstein + + * Java/clang/flowing/: Flowing.java, FlowingClang.java, + StackFrame.java, StackFrameReal.java, StackFrameVirtual.java: A + newer flowing clang version + +2000-11-16 Thursday 20:28 Benjamin Fallenstein + + * Java/DimRecursor.java, Java/Iter.java, + Java/flob/EnumVanishingView.zob, Modules/iter/.cvsignore, + Modules/iter/DimRecursor.java, Modules/iter/EnumVanishingView.zob, + Modules/iter/Iter.java, Modules/iter/README: Move iteration + experiments into Modules/ + +2000-11-16 Thursday 00:25 Tuomas J. Lukka + + * Java/part/: GenTreePartModel.java, GenTreeTestModel.java: More + work on tree-like parts: define a general interface. This makes the + code a bit simpler and now we can use this on nile. Excellent... + +2000-11-15 Wednesday 16:26 Tuomas J. Lukka + + * Java/arch/java2d/ZZDrawingJ2D.java: Lesser quality settings + +2000-11-13 Monday 11:59 Tuomas J. Lukka + + * Java/part/ImpliedTreePart2.java: Use parsed IDs. Improvement? + +2000-11-13 Monday 11:59 Tuomas J. Lukka + + * Java/: ZZSpacePart.java, part/ImpliedTreePart.java: Rationalize + +2000-11-13 Monday 11:58 Tuomas J. Lukka + + * Java/ZZCellHandle.java: Optimize + +2000-11-10 Friday 17:45 Benjamin Fallenstein + + * Java/flob/FlobFactory.java: An iteration draft which abstracts + the dimension recursion out; a not-yet-really-working version of + the Vanishing view in less than 175 lines, using that; functions to + place flobs visual center to visual center. + +2000-11-10 Friday 09:59 Antti-Juhani Kaijanaho + + * Documentation/wmlinc/catart.wml: (hopefully) fix anchoring + +2000-11-07 Tuesday 23:07 Tuomas J. Lukka + + * Java/: ZZSlicedDimSpace.java, storage/Sliced.java, + storage/SlicedCursor.java, storage/SlicedHomes.java, + storage/SlicedSame.java: Remove compilation warnings. Start work on + a sequence-implied tree + +2000-11-07 Tuesday 13:06 Antti-Juhani Kaijanaho + + * Java/flob/RowColRaster.zob: merge + +2000-11-07 Tuesday 12:38 Antti-Juhani Kaijanaho + + * Java/flob/CompassRaster.zob, Java/flob/CompassView.zob, + Java/flob/FlobRaster.java, Java/flob/ICView.zob, + Java/flob/Level.java, Java/flob/LevelRaster.zob, + Java/flob/LevelView.zob, Java/flob/ManyToManyRaster.zob, + Java/flob/ManyToManyView.zob, Java/flob/NullRaster.zob, + Java/flob/NullView.zob, Java/flob/RasterCellFactory1.zob, + Java/flob/RasterCellFactory2.zob, Java/flob/RasterFlobFactory.java, + Java/flob/RowColView.zob, Java/flob/SimpleFlobRaster.zob, + Java/flob/SimpleFlobView.zob, Java/flob/TreeRaster.zob, + Java/flob/TreeView.zob, Java/flob/VStreamRaster.zob, + Modules/daytimedemo/Calendar2.zob, + Modules/daytimedemo/DayTimeDemo.zob, Modules/mbox/SingleMail.zob: + merge + +2000-11-06 Monday 12:39 Tuomas J. Lukka + + * Java/part/: BinaryTreePart.java, DoubleStepPart.java, + ZZROSpacePart.java, ZZROStrSpacePart.java: An amusing new space + part: double-step dimensions + +2000-11-06 Monday 12:06 Antti-Juhani Kaijanaho + + * Java/clang/heraclitus/.cvsignore, Modules/daytimedemo/.cvsignore, + Modules/hypergenealogy/.cvsignore, Modules/mbox/ZZMbox.java: + merging from 0.2 branch + +2000-11-05 Sunday 19:11 Tuomas J. Lukka + + * Java/: ZZRODimension.java, storage/SlicedOV.java, + storage/SlicedStpr.java: BIG change. Please test, as things may be + BADLY broken. Change ZZDimension to use ZZCellHandles instead of + Strings, based on the potentially faulty assumption that + ZZCellHandles are a good idea. This is very experimental. + +2000-11-05 Sunday 18:22 Tuomas J. Lukka + + * Java/arch/javadoc/ZobDoc.java: First working version of ZOb docs. + +2000-11-05 Sunday 12:51 Tuomas J. Lukka + + * Java/.cvsignore: Add generated zob documentation + +2000-11-05 Sunday 12:49 Tuomas J. Lukka + + * Modules/openGL/ZZOpenGLGraphics.java: Start work on a doclet for + generating ZOb structparam docs. The point is to leave out the + things that are not interesting for use in the structure. + +2000-11-03 Friday 08:25 Antti-Juhani Kaijanaho + + * Java/: clang/ZZClangOps.pl, storage/Recs.pl: much better file by + perl generation + +2000-11-03 Friday 08:01 Antti-Juhani Kaijanaho + + * Java/media/Scroll.java, Java/storage/DimHash.java, + Java/storage/DirSet.java, Java/storage/WritableHash.java, + Java/storage/WritableSet.java, Modules/xml/XML.java: hopefully + final 0.1.x merge + +2000-11-03 Friday 06:47 Antti-Juhani Kaijanaho + + * Java/storage/Recs.java: generated file OUT! + +2000-11-02 Thursday 13:03 Tuomas J. Lukka + + * Java/LoopDetector.java: Important: use .equals instead of == for + comparison. + +2000-11-02 Thursday 13:01 Tuomas J. Lukka + + * Java/ZZDrawing.java: Rendering quality: I want my antialiased + fonts antialiased. + +2000-11-01 Wednesday 08:12 Tuomas J. Lukka + + * Java/: ZZCanvasView.java, ZZPhotoView.java, + media/ZZSoundView.java: Make painting always happen into + doublebuffer. + +2000-11-01 Wednesday 00:39 Tuomas J. Lukka + + * Java/: ZZIter.java, flob/StdLinks.zob: Various fixes to views, + including curving. Not complete yet: need to add bulge. + +2000-10-31 Tuesday 15:12 Tuomas J. Lukka + + * Java/TestSpace.java: First optional architecture: Java2D. If you + have Java2D in your compilation *and* execution environment and use + 'make ARCH=java2d', you'll get translucent cells. We can use the + improved rendering of Java2D now. + +2000-10-31 Tuesday 14:20 Antti-Juhani Kaijanaho + + * Documentation/UsersGuide/Makefile: fix a bug + +2000-10-31 Tuesday 14:01 Antti-Juhani Kaijanaho + + * Documentation/: lib.mk, wmlinc/article.wml, wmlinc/common.wml: + first version of cat's UG - talk to her if you want to work on it + +2000-10-30 Monday 15:25 Tuomas J. Lukka + + * Java/: ZZModule.java, flob/VanishingRaster.zob: VanishingRaster + -> vanishingview + +2000-10-30 Monday 10:44 Tuomas J. Lukka + + * Java/ZZModules.java: Why would we need an extra ZZModules class + after all? + +2000-10-29 Sunday 19:34 Tuomas J. Lukka + + * Modules/wordnet/conv.pl: Longer func name, for a change. Count + better. Make deleteFromRank called excise. + +2000-10-29 Sunday 19:19 Tuomas J. Lukka + + * Java/TimeTest.java: Twiddle + +2000-10-27 Friday 13:55 Tuomas J. Lukka + + * Java/flob/BallCell.java: Oops, forgot to add + +2000-10-26 Thursday 18:15 Tuomas J. Lukka + + * Java/flob/LineDecor.java: Fix dbg + +2000-10-26 Thursday 18:15 Tuomas J. Lukka + + * Java/flob/Colorer.java: A bit more structure + +2000-10-26 Thursday 18:14 Tuomas J. Lukka + + * Java/flob/CellBgFlob.java: Adjust for colorer + +2000-10-26 Thursday 18:09 Tuomas J. Lukka + + * Java/: SafeExit.java, UndoList.java, d.java, + errors/ZZInvalidCursorPositionError.java, flob/ArrowDecor.java, + flob/FlobDecorator.java: More javadoc comments + +2000-10-26 Thursday 13:08 Antti-Juhani Kaijanaho + + * Documentation/: keybindings.wml, Spec/Makefile: merge + +2000-10-26 Thursday 12:25 Antti-Juhani Kaijanaho + + * Java/NEWS (ver_0_1): oops, move NEWS to toplevel dir + +2000-10-22 Sunday 09:15 Tuomas J. Lukka + + * Java/flob/MagGrid.zob: Decrease trybefore a bit for smoother + animation + +2000-10-21 Saturday 23:07 Tuomas J. Lukka + + * Java/flob/GridGeom.java: Start reimplementing row-column stuff. + The aim is to get a cleaner abstraction so that we can start + bootstrapping by rewriting the new, easy code using cells. + +2000-10-21 Saturday 13:46 Tuomas J. Lukka + + * Java/README: Update requirements + +2000-10-21 Saturday 13:45 Tuomas J. Lukka + + * Documentation/Gentle_Introduction/gi.wml: Rewrite the whole XML + import / export stuff. We really don't want DOM to load the whole + document in memory but SAX since we can just stream off the tags. + This should make import/export of large amounts of stuff faster, + just what we need for the wordnet demo... + +2000-10-20 Friday 15:47 Benjamin Fallenstein + + * Java/ZZRasterDirection.java: This doesn't make sense to me + anymore... + +2000-10-20 Friday 15:16 Benjamin Fallenstein + + * Java/clang/flowing/X.java: Change back earlier i18n attempt + +2000-10-20 Friday 11:35 Tuomas J. Lukka + + * Java/RString.java: This may become something eventually - + referential strings as objects. I'll have to talk with Ted about + what a cell should really be able to contain + +2000-10-19 Thursday 17:04 Tuomas J. Lukka + + * Java/media/: ZZDefaultText.java, ZZText.java: Next draft + +2000-10-18 Wednesday 14:35 Tuomas J. Lukka + + * Java/ZZConnection.java, Java/ZZPath.java, + Java/clang/ZZClang1.java, Java/clang/ZZClangContextReal.java, + Java/clang/flowing/T.java, Java/clang/heraclitus/PS1.java, + Java/clang/thales/Environment.java, + Java/clang/thales/SyntaxForm.java, Java/clang/thales/Task.java, + Java/clang/thales/syntaxforms/Abstraction.java, + Java/clang/thales/syntaxforms/CellDenoter.java, + Java/clang/thales/syntaxforms/CellLiteral.java, + Java/clang/thales/syntaxforms/Primitive.java, + Java/clang/thales/syntaxforms/Sequence.java, + Java/transform/ChangeDim.java, Java/transform/ClearDim.java, + Java/transform/CopyDim.java, Java/transform/FoldDim.java, + Java/transform/ReverseDim.java, Java/transform/Version0.java, + Modules/database/DB0.java, Modules/openGL/OpenGLCloud.java, + Modules/sound/ZZPlayer.java, Modules/test/TestClang1.java, + Modules/test/TestHuge.java: HUGE HUGE HUGE change. Global replace + all getNeighbours, getHeadcells and newCells. Now the code should + be a lot cleaner-looking... + +2000-10-17 Tuesday 11:05 Tuomas J. Lukka + + * Documentation/FAQ: Clarify who programs and who doesn't (someone + got confused) + +2000-10-17 Tuesday 08:01 Antti-Juhani Kaijanaho + + * CODING: Recommend ZZLogger. + +2000-10-13 Friday 13:52 Benjamin Fallenstein + + * Java/clang/flowing/: B.java, C.java, Primitive.java, + PrimitiveSet.java: Improve flowing + +2000-10-11 Wednesday 13:28 Antti-Juhani Kaijanaho + + * Java/clang/heraclitus/HeraclitusCommand.java: oops + +2000-10-10 Tuesday 09:03 Antti-Juhani Kaijanaho + + * Documentation/diagrams/Makefile: another merge + +2000-09-29 Friday 12:34 Antti-Juhani Kaijanaho + + * README: Demo for cat: added a space. + +2000-09-23 Saturday 12:00 Antti-Juhani Kaijanaho + + * cvsparser.pl, Documentation/ApplitudeWriters/Makefile, + Documentation/Clang_Design/Makefile, + Documentation/CyberText/Makefile, + Documentation/DesignProblems/Makefile, + Documentation/DimBased/Makefile, + Documentation/Gentle_Introduction/Makefile, + Documentation/Glossary/Makefile, Documentation/Math/Makefile: + another merge + +2000-09-19 Tuesday 10:31 Antti-Juhani Kaijanaho + + * Documentation/Glossary/gl.wml, Java/ChkVersion.java, + Java/NullZOb.java, Java/SoundObs.java, Java/ZZEvObs.java, + Java/ZZExec.java, Java/ZZKeyBindings.java, + Java/ZZKeyBindings0.java, Java/ZZObs.java, Java/ZZObsTrigger.java, + Java/ZZScene.java, Java/ZZTraverseCB.java, Java/ZZView.java, + Java/clang/ZZClangContext.java, + Java/clang/ZZClangContextVirtual.java, Java/clang/ZZClangOp.java, + Java/errors/ZZConnectWouldBreakError.java, + Java/errors/ZZError.java, Java/errors/ZZFatalError.java, + Java/errors/ZZInfiniteLoop.java, + Java/errors/ZZInvalidDimensionError.java, Java/flob/BeamDecor.java, + Java/flob/CellFlob1.java, Java/flob/ConnectionLineDecor.java, + Java/flob/SimpleBeamer.zob, Java/flob/SimpleFlobConnector.zob, + Java/flob/SpanFlob.java, Java/flob/TextDecor.java, + Java/media/Address.java, Java/media/ByteScroll.java, + Java/media/CharScroll.java, Java/media/LineBreaker.java, + Java/media/LineInfo.java, Java/media/SimpleLineBreaker.java, + Java/media/SimpleLineInfo.java, Java/media/SoundScroll.java, + Java/media/Span.java, Java/media/SpanSet.java, + Java/media/SpanTree.java, Java/media/ZZHumber.java, + Java/storage/ContentHash.java, Java/storage/ContentStore.java, + Java/storage/ContentStorer.java, Java/storage/DimStore.java, + Java/storage/FileWritable.java, Java/storage/Flushable.java, + Java/storage/GZZ0.java, Java/storage/SimpleContentFile.java, + Java/storage/SimpleDimFile.java, Java/storage/TestDimHash.java, + Java/storage/Writable.java, Java/storage/WritableIS.java, + Java/storage/ZZCacheContentStore.java, + Java/storage/ZZDimStorer.java, Java/transform/Version1.java, + Java/transform/Version2.java, Java/transform/VersionChanger.java, + Modules/extern/Extern.java, Modules/joystick/LinuxJoystick.java, + Modules/mbox/ZZDateParser.java, Modules/prez/Prez.java: another + merge + +2000-09-19 Tuesday 09:45 Tuomas J. Lukka + + * INSTALL: test lock release + +2000-09-18 Monday 14:28 Tuomas J. Lukka + + * Java/storage/: DirStreamSet.java, StreamSet.java: Add deletion of + extra cells associated with cursors + +2000-09-17 Sunday 23:50 Tuomas J. Lukka + + * Documentation/Syntaxless/synt.wml: Start writing + +2000-09-17 Sunday 23:44 Tuomas J. Lukka + + * Java/Cell.java: This doesn't have much to give any more... + +2000-09-17 Sunday 13:45 Antti-Juhani Kaijanaho + + * Java/clang/heraclitus/PrimitiveSet.java: merge again, also fixing + the brokenness of previous merge + +2000-09-17 Sunday 13:07 Antti-Juhani Kaijanaho + + * Java/BuildInfo.java.in, Java/ZZLogger.java, + Java/ZZPrimitiveCommand.zob, Java/clang/thales/DimensionNames.java, + Java/clang/thales/Evaluator.java, + Java/clang/thales/PrimitiveOperation.java, + Java/clang/thales/Refcounted.java, + Java/clang/thales/ThalesClang.java, + Java/clang/thales/ThalesProgram.zob, + Java/clang/thales/primitives/If.java, + Java/script/ZZScriptPerl.java, Modules/applet/example1.html: merge + from stable branch, does not compile + +2000-09-15 Friday 09:51 Antti-Juhani Kaijanaho + + * makedist.sh, manifest-filter.lst (ver_0_1): dist maker fixes + +2000-09-14 Thursday 16:10 Antti-Juhani Kaijanaho + + * .cvsignore, makedist.param: merge from ver_0_1 + +2000-09-13 Wednesday 15:06 Tuomas J. Lukka + + * Documentation/CyberText/: 1.png, 3.png, 4.png, ct.wml, + kello-o.png, kello.png, vilma.png: Put in new version + +2000-09-13 Wednesday 14:58 Tuomas J. Lukka + + * Documentation/CyberText/ct-old.wml: Save old version in current + tree as well + +2000-09-13 Wednesday 14:55 Tuomas J. Lukka + + * Documentation/Gentle_Introduction/zzgentle.tex: Start html + conversion + +2000-09-13 Wednesday 14:54 Tuomas J. Lukka + + * Documentation/Spec/zzspec.wml: add summary of dims (to be grown) + +2000-09-12 Tuesday 17:12 Tuomas J. Lukka + + * Documentation/UsersGuide/ug.wml: Improve + +2000-09-09 Saturday 13:37 Tuomas J. Lukka + + * Documentation/STARTING: Update + +2000-09-09 Saturday 09:32 Tuomas J. Lukka + + * Java/storage/: MultiFile.java, WriteCacheOp.java: Mark various + storage files deprecated + +2000-09-08 Friday 09:53 Antti-Juhani Kaijanaho + + * Java/clang/thales/Primitive.java: move Primitive to syntaxforms + +2000-09-07 Thursday 22:57 Tuomas J. Lukka + + * Documentation/UsersGuide/: clone1.png, clone2.png, connect1.png, + connect2.png: Add clones + +2000-09-07 Thursday 22:42 Tuomas J. Lukka + + * Documentation/UsersGuide/: bothwins.png, edit1.png, edit2.png, + edit3.png, edit4.png, rightmoved.png, showingz.png: User's guide, + first half of first draft + +2000-09-07 Thursday 18:27 Tuomas J. Lukka + + * Documentation/CellScroll/: .cvsignore, Makefile, cs.ptex: Remove + old crud + +2000-09-07 Thursday 12:34 Antti-Juhani Kaijanaho + + * Documentation/Clang_Design/thales.wml: markup fix + +2000-09-06 Wednesday 05:30 Antti-Juhani Kaijanaho + + * Java/clang/thales/.cvsignore: ignore generated file + +2000-09-04 Monday 19:10 Tuomas J. Lukka + + * Java/storage/ZZWriteCacheDimension.java: First undo test working + +2000-08-29 Tuesday 07:39 Antti-Juhani Kaijanaho + + * Java/ZZEventQueue.java: ZZEventQueue is not used anywhere + +2000-08-28 Monday 11:12 Antti-Juhani Kaijanaho + + * Java/Next.java: seems to be superseded by ZZDimSpace.IDDimension + +2000-08-27 Sunday 14:20 Benjamin Fallenstein + + * Java/ZZClangOps.java: Now what was this doing here? + +2000-08-27 Sunday 08:40 Tuomas J. Lukka + + * Java/: ZZHash.java, ZZHashObs.java, ZZViewObs.java: And some + more. Lots of evolution has been going on, apparently. + +2000-08-27 Sunday 08:37 Tuomas J. Lukka + + * Java/: ZZAbstractClient.java, ZZJavaRegistry.java, + ZZLinkRenderer.java, ZZLinkRenderer1.java, ZZRank.java: Remove more + old cruft. The nightly jars are already down to 297k from 350k... I + wonder how low we can go ;) + +2000-08-26 Saturday 21:51 Tuomas J. Lukka + + * Java/example1.html: Move it to where it should be + +2000-08-25 Friday 02:55 Tuomas J. Lukka + + * Java/TODO: Mention sf task manager + +2000-08-24 Thursday 19:21 Tuomas J. Lukka + + * Java/: ZZCanvas.java, ZZCanvasCell1.java, ZZCanvasCellBg.java, + ZZCanvasTextSpanSet.java, ZZGraphics.java, ZZPathCoordRaster.java, + ZZRaster.java, ZZTreeRaster.java, ZZVanishingRaster.java, + media/TestSpans.java, media/VStreamRenderer.java, + media/ZZCanvasBeamThing.java, media/ZZCanvasTextMark.java, + media/ZZCanvasTextSpan.java: Remove a LOT of crud! I wonder how + much the next .jar files will be smaller by... + +2000-08-24 Thursday 10:48 Tuukka Hastrup + + * Modules/database/: zz.queries, zz.sql: SQL samples we used in the + demo + +2000-08-22 Tuesday 19:46 Tuukka Hastrup + + * Modules/xml/: XML2ZZ.java, ZZXML1.java: New XML import/export is + "complete". Removing old versions. + +2000-08-21 Monday 18:12 Tuukka Hastrup + + * Java/storage/.cvsignore: Obvious ;-) One more autogenerated file. + +2000-08-21 Monday 18:10 Tuukka Hastrup + + * Java/ZZLocal.java, Java/ZZRemote.java, Java/ZZSimpleEdit.java, + Java/storage/TestScroll.java, Java/storage/ZZCellScroll.java, + Modules/xml/TestXML.java: Old test implementations of space and + related files removed. + +2000-08-19 Saturday 12:16 Antti-Juhani Kaijanaho + + * Documentation/Clang_Design/design.ptex: oops + +2000-08-19 Saturday 05:35 Tuukka Hastrup + + * Modules/database/createscript.pl: Polishing things up for a demo + +2000-08-18 Friday 22:52 Tuomas J. Lukka + + * Modules/: prez/.cvsignore, textcloud/.cvsignore: Ignore cvs + +2000-08-17 Thursday 12:56 Tuomas J. Lukka + + * Documentation/ApplitudeWriters/appw.wml: Doc changes + +2000-08-15 Tuesday 11:58 Antti-Juhani Kaijanaho + + * Java/clang/thales/README: Initial revision. + +2000-08-15 Tuesday 05:19 Tuomas J. Lukka + + * Documentation/DesignProblems/dp.wml: Solve (?) versioning problem + +2000-08-14 Monday 19:22 Tuomas J. Lukka + + * Java/TextCloud.java: Change textcloud into ZOb + +2000-08-11 Friday 10:43 Tuukka Hastrup + + * Modules/mbox/MailRaster.zob: Forgot to commit this removal. + +2000-08-10 Thursday 22:14 Tuukka Hastrup + + * Modules/mbox/.cvsignore: Renamed MailRaster to SingleMail. + +2000-08-05 Saturday 22:27 Benjamin Fallenstein + + * Documentation/misc/Curseling: Cursor selection (curseling) doc + (XXX zzspec not yet updated) + +2000-08-03 Thursday 20:41 Tuomas J. Lukka + + * Java/: ZZGlobal.java, ZZList.java: LOTS of changes: ZZObs should + work again, things should be a little faster and some things are + deprecated. I may have broken something, please tell me if I did. + +2000-07-28 Friday 08:36 Tuomas J. Lukka + + * Documentation/Spec/email1.dia: New diagram + +2000-07-27 Thursday 10:15 Tuukka Hastrup + + * Java/flob/FlatRaster.zob: Renamed FlatRaster as CompassRaster. + Shows all the connections from accursed cell. Draft + +2000-07-23 Sunday 23:39 Tuomas J. Lukka + + * Java/ZZAbstractView.java: Good riddance, once more. + +2000-07-23 Sunday 23:11 Tuomas J. Lukka + + * Java/ZZSimpleClient2.java: Good riddance, you, too ;) + +2000-07-23 Sunday 14:50 Tuomas J. Lukka + + * Java/media/ZZSoundCanvasComb.java: Start removal of swing. + +2000-07-22 Saturday 18:14 Tuomas J. Lukka + + * Java/ZZTextView.java: Good riddance ;) + +2000-07-18 Tuesday 09:34 Antti-Juhani Kaijanaho + + * Java/flob/VanishingRaster.java: Ignore generated files + +2000-07-18 Tuesday 05:21 Antti-Juhani Kaijanaho + + * Documentation/Math/math.ptex: Make the ZZSpace definition a + little more explicit. + +2000-07-17 Monday 22:02 Tuomas J. Lukka + + * Java/ZZDummyGraphics.java: Obsolete + +2000-07-14 Friday 00:15 Tuomas J. Lukka + + * Documentation/Spec/inheritparam.dia: Update + +2000-07-11 Tuesday 12:30 Tuomas J. Lukka + + * Java/clang/.cvsignore: Small tidy-ups + +2000-07-11 Tuesday 12:22 Tuomas J. Lukka + + * Java/: ZZClang1.java, ZZClangContext.java, + ZZClangContextReal.java, ZZClangContextVirtual.java, + ZZClangOp.java, ZZClangOps.pl: Move clang stuff to its own subdir + +2000-07-11 Tuesday 11:10 Tuomas J. Lukka + + * Java/: ZZConnectWouldBreakError.java, ZZError.java: Slightly more + graceful error handling. + +2000-07-09 Sunday 20:50 Tuomas J. Lukka + + * Java/RasterFlobFactory.java: Move flobstuff + +2000-07-09 Sunday 14:31 Tuomas J. Lukka + + * Documentation/README: Add keybindings + +2000-07-09 Sunday 12:20 Tuomas J. Lukka + + * Java/: Flob.java, FlobSet.java: Move flob-related stuff to flob/. + Add Renderable for decorations and as a base class. We're close + now. + +2000-07-07 Friday 18:34 Tuomas J. Lukka + + * Java/make-src-tree.sh: Doc generation patch from Tuukka + +2000-07-04 Tuesday 19:02 Tuomas J. Lukka + + * Java/FlobFactory.java: Move FlobFactory to RasterFlobFactory - + it's more for rasters than general flob stuff + +2000-07-04 Tuesday 18:25 Tuomas J. Lukka + + * Java/ZZHomeComb.java: Some flob work + +2000-07-04 Tuesday 17:40 Tuomas J. Lukka + + * Java/: ZZFlobDim.java, ZZFlobIter.java, ZZFlobIterable.java, + ZZFlobRenderer.java: Remove old attempts in order not to confuse + people + +2000-07-03 Monday 22:26 Tuomas J. Lukka + + * Documentation/Spec/: canvasraster.dia, cursor1.dia, + cursordim.dia, rasterspec.dia: Talk about rasters + +2000-07-02 Sunday 21:42 Tuomas J. Lukka + + * Documentation/Spec/zzspec.ptex: Start htmlization + +2000-06-21 Wednesday 19:34 Vesa Parkkinen + + * Documentation/CyberText/email.dia: overview, more to come. + Tomorrow... + +2000-06-13 Tuesday 11:34 Tuomas J. Lukka + + * Documentation/DesignProblems/: beamorder.dia, linkorder.dia: add + +2000-06-03 Saturday 09:41 Vesa Parkkinen + + * Modules/xml/old2xml.pl: fixes, to be cleaned + +2000-05-29 Monday 21:26 Tuomas J. Lukka + + * Modules/openGL/: Makefile, ZZOpenGLGraphics.cc: Add comments + +2000-05-26 Friday 10:14 Tuomas J. Lukka + + * Documentation/CyberText/permascroll.dia: Oops + +2000-05-26 Friday 10:08 Vesa Parkkinen + + * Modules/openGL/fi_iki_lukka_ZZOpenGLGraphics.h: some simple + code... + +2000-05-22 Monday 16:48 Tuomas J. Lukka + + * Documentation/CyberText/: rank2vert.dia, rank3both.dia: oops + +2000-05-21 Sunday 00:47 Tuomas J. Lukka + + * Documentation/CyberText/rank1vert.dia: First figure... more to + follow + +2000-05-20 Saturday 15:55 Tuomas J. Lukka + + * Java/: ZZCellRenderer.java, ZZCellRenderer1.java: Restart now + retains TextCloud window. + +2000-05-19 Friday 01:46 Tuomas J. Lukka + + * Java/ZZSingleCellView.java: Discard singlecellview + +2000-05-16 Tuesday 14:57 Tuomas J. Lukka + + * Documentation/: diagrams/ZZCanvas.dia, diagrams/cursoring.dia, + misc/RENDERING: Diagrams + +2000-05-14 Sunday 18:31 Tuomas J. Lukka + + * Java/StringScroll.java: ... + +2000-05-09 Tuesday 17:29 Tuomas J. Lukka + + * Java/: Test1.java, ZZ2DBlob.java, ZZ2DCanvas.java, + ZZ2DCanvasGridRaster.java, ZZ2DCanvasRaster.java, + ZZ2DCanvasVanishingRaster.java, ZZ2DCanvasView.java: Speedup, + cleanup + +2000-05-08 Monday 23:56 Tuomas J. Lukka + + * Documentation/misc/: billow, textcloud: X + +2000-05-08 Monday 01:37 Tuomas J. Lukka + + * TODO: ... + +2000-05-03 Wednesday 04:30 Vesa Parkkinen + + * C++/: Data.cpp, Data.h, INSTALL, Makefile, Makefile.in, + Renderer.cpp, Renderer.h, ZZ2DGrid.cpp, ZZ2DGrid.h, ZZ2DRaster.h, + ZZ2DRaster_Col.cpp, ZZ2DRaster_Col.h, ZZ2DRaster_Row.cpp, + ZZ2DRaster_Row.h, ZZ2DRaster_Soft1.cpp, ZZ2DRaster_Soft1.h, + ZZ2DRaster_Soft2.cpp, ZZ2DRaster_Soft2.h, ZZ2DRaster_SoftRow.cpp, + ZZ2DRaster_SoftRow.h, ZZCell.cpp, ZZCell.h, ZZCliComm.cpp, + ZZCliComm.h, ZZClient.cpp, ZZClient.h, ZZClientInterface.h, + ZZClientViewIf.h, ZZFileHandler.cpp, ZZFileHandler.h, + ZZFileHandlerInterface.h, ZZId.h, ZZScript.cpp, ZZScript.h, + ZZScriptAPI_1.h, ZZScriptInterface.h, ZZScriptServerInterface.h, + ZZServer.cpp, ZZServer.h, ZZServerInterface.h, ZZSettings.h, + ZZView.cpp, ZZView.h, configure, configure.in, main.cpp, main.h: + removed c++-version again : + ------------------------------------------------------------------- + --- + +2000-05-03 Wednesday 03:06 Tuomas J. Lukka + + * Documentation/misc/keys: foo + +2000-05-03 Wednesday 03:04 Tuomas J. Lukka + + * Java/ZZCanvasVanishingRaster.java: Flobs. Whew. + +2000-05-02 Tuesday 10:15 Vesa Parkkinen + + * C++/README: removed c++ version + +2000-05-01 Monday 04:21 Tuomas J. Lukka + + * Java/ZZ2DCanvasButteredRaster.java: Improve new canvas + +2000-04-30 Sunday 11:41 Tuomas J. Lukka + + * Java/: ContentHash.java, ContentStore.java, DimHash.java, + DimStore.java, DirSet.java, MultiFile.java, Recs.java, Recs.pl, + Sliced.java, SlicedOV.java, SlicedStpr.java, TestDimHash.java, + TestScroll.java, Writable.java, WritableHash.java, WritableIS.java, + WritableSet.java, ZZCellScroll.java, ZZPersistentDimSpace.java, + ZZPersistentDimension.java: More reorg + +2000-04-30 Sunday 11:36 Tuomas J. Lukka + + * Java/: Address.java, ByteScroll.java, CharScroll.java, + Scroll.java, SoundScroll.java, Span.java, SpanTree.java, + TestSpans.java, VStream.java, VStreamRenderer.java, + ZZCanvasBeamThing.java, ZZCanvasTextMark.java, + ZZCanvasTextSpan.java, ZZHumber.java, ZZSoundCanvasComb.java, + ZZSoundView.java, media/README: Reorg + +2000-04-30 Sunday 11:26 Tuomas J. Lukka + + * Java/: ZZMarkView.java, ZZMouseListener.java: Remove refs to + swing + +2000-04-13 Thursday 14:09 Tuomas J. Lukka + + * Java/ZZCompound.java: cursor + +2000-04-06 Thursday 03:22 Tuomas J. Lukka + + * Documentation/Gentle_Introduction/.cvsignore: Twid + +2000-03-28 Tuesday 12:51 Vesa Parkkinen + + * Modules/README: added applet + +2000-03-28 Tuesday 07:54 Vesa Parkkinen + + * Java/ZZApplet.java: moved to Modules + +2000-03-13 Monday 00:19 Tuomas J. Lukka + + * Java/check.pl: Make view font etc selection simpler + +2000-03-12 Sunday 10:57 Tuomas J. Lukka + + * Java/.gvimrc: Add help + +2000-03-12 Sunday 10:55 Tuomas J. Lukka + + * Documentation/Slices/SliceLogic, + Documentation/Slices/zzSliceLogic.jpg, Java/ZZSliced.java: Small + things + +2000-03-06 Monday 05:36 Vesa Parkkinen + + * Java/: Scene.java, ZZRenderer3d.java: removed 3d code + +2000-03-04 Saturday 15:45 Tuomas J. Lukka + + * Documentation/DimBased/dim.ptex: add docs + +2000-02-29 Tuesday 00:42 Tuomas J. Lukka + + * Java/ZZEdit.java: edit to space change + +2000-02-20 Sunday 17:33 Tuomas J. Lukka + + * Java/: TestXML.java, ZZXML1.java: Make XML a module + +2000-02-19 Saturday 18:06 Tuomas J. Lukka + + * Documentation/Clang_Design/.cvsignore, + Documentation/Interfacing/.cvsignore, + Documentation/Spec/.cvsignore, Java/ZZ2DGrid.java, + Java/ZZ2DGridRaster.java, Java/ZZ2DGridRasters.java, + Java/ZZ2DGridView.java: Remove 2dgrid legacy code + +2000-02-19 Saturday 18:01 Tuomas J. Lukka + + * Modules/test/README: Clang WORKS + +2000-02-08 Tuesday 00:40 Tuomas J. Lukka + + * Java/ZZ2DCanvasRasters.java: Many small things, cleaning reorg + +2000-02-03 Thursday 09:35 Vesa Parkkinen + + * Java/script/Makefile: [no log message] + +2000-02-01 Tuesday 23:06 Tuomas J. Lukka + + * Perl/README: Preparing for 0.01 + +2000-01-30 Sunday 19:39 Tuomas J. Lukka + + * Java/Package.html: Simplification of space code - preparing for + transients + +2000-01-27 Thursday 18:00 Tuomas J. Lukka + + * Documentation/Interfacing/Makefile: Doc makefiles + +2000-01-26 Wednesday 18:28 Tuomas J. Lukka + + * Java/ZZObsCaster.java: New event model ++ + +2000-01-03 Monday 02:35 Tuomas J. Lukka + + * Java/: ZZ2DGridComponent.java, ZZSimpleClient.java: Getting + there... + +2000-01-01 Saturday 00:52 Tuomas J. Lukka + + * Java/: ZZBrowse.java, ZZVCell.java: Reshaping and + undinosaurifying + +1999-12-24 Friday 16:33 Tuomas J. Lukka + + * Documentation/CellScroll/SCRATCH: Ignoring stuff... + +1999-12-24 Friday 16:30 Tuomas J. Lukka + + * Documentation/Gentle_Introduction/README: foo + +1999-12-23 Thursday 01:53 Tuomas J. Lukka + + * Documentation/Interfacing/int.ptex: Add rcs info to doc files + +1999-12-23 Thursday 01:44 Tuomas J. Lukka + + * Documentation/Clang_Design/design.pod: Change format + +1999-12-09 Thursday 16:15 Tuomas J. Lukka + + * Java/script/: ZZScriptAPI_1_JNI.h, ZZScriptPerl.cpp: Minor + JNIPerl fixes + +1999-12-09 Thursday 13:13 Tuomas J. Lukka + + * Java/script/: ZZScriptAPI_1_JNI.cpp, invoke.c: foo + +1999-12-09 Thursday 01:31 Tuomas J. Lukka + + * Java/script/ZZId.h: Start jni-perl + +1999-12-04 Saturday 18:01 Tuomas J. Lukka + + * Documentation/: PROTOCOL, misc/ADDRESSING, misc/TORESOLVE: foo + +1999-12-04 Saturday 17:37 Tuomas J. Lukka + + * LICENSE.lgpl, LICENSE.xpl, VERSION, Perl/PerlServImpl.pm, + Perl/ZZPerlDBServ.pm, Perl/ZZPerlServ.pm, + Perl/ZZPerlSimpleClient.pm, Perl/cperl.pl, Perl/sperl.pl: foo + diff --git a/Documentation/ApplitudeWriters/Makefile b/Documentation/ApplitudeWriters/Makefile new file mode 100644 index 0000000..05b5117 --- /dev/null +++ b/Documentation/ApplitudeWriters/Makefile @@ -0,0 +1,10 @@ +DIAGRAMS=../wmlinc/article.wml +# rank1vert.png rank2vert.png rank3both.png permascroll.png + +all: appw.html appw-ns4.html + +appw.html: appw.wml $(DIAGRAMS) + +appw-ns4.html: appw.wml $(DIAGRAMS) + +include ../lib.mk diff --git a/Documentation/ApplitudeWriters/appw.wml b/Documentation/ApplitudeWriters/appw.wml new file mode 100644 index 0000000..6eb0861 --- /dev/null +++ b/Documentation/ApplitudeWriters/appw.wml @@ -0,0 +1,90 @@ + + + +{: [[s/\bZZModule\b/\1<\/code>]] + + + + Applitude Writer's Guide + +#include '../wmlinc/article.wml' + + + + + +

Applitude Writer's Guide

+
$Id: appw.wml,v 1.1 2000/08/17 12:56:45 tjl Exp $
+ + Tuomas Lukka
+
+ + + +
+ + + + + + +Applitudes are the preferred way of including more functionality into +GZigZag. This document explains how they are written. + + + +

Introduction

+ +

+ An applitude is basically a view and related actions. + +

ZZModule

+ +

+ The ZZModule abstract class provides the basic mechanism for + including Java code into GZigZag without having to modify and/or + recompile GZigZag. GZigZag uses the Java reflection API to connect + to new modules. + +

+ The ZZModule architecture is slightly different than one might + expect: instead of directly inheriting from the class, + modules use a static member which is a ZZModule: for example, + +

+public class TextCloud implements ... {
+	...
+	static public ZZModule module = new ZZModule() {
+		public void action(String id, ...) {
+			... execute action id
+		}
+		public ZOb newZOb(String id) {
+			... return a new ZOb instance with the given
+			    name
+		}
+	};
+}
+
+ + +
+ + + +:} + + + diff --git a/Documentation/CellScroll/SCRATCH b/Documentation/CellScroll/SCRATCH new file mode 100644 index 0000000..1215701 --- /dev/null +++ b/Documentation/CellScroll/SCRATCH @@ -0,0 +1,8 @@ + + +As a synching method, it is made so that the file is +4k-aligned, i.e. no records (except those that are longer than 4k by themselves) +are allowed to cross a 4-k boundary. Zero padding is added to fill +the gap. This of course requires that the first byte of a magic no is never +zero --- then a zero can be interpreted to mean ``jump to the next 4k limit''. + diff --git a/Documentation/Clang_Design/Makefile b/Documentation/Clang_Design/Makefile new file mode 100644 index 0000000..bdd274d --- /dev/null +++ b/Documentation/Clang_Design/Makefile @@ -0,0 +1,11 @@ +DEP=../wmlinc/article.wml + +all thales: thales.html thales-ns4.html + +thales.html: thales.wml $(DIAGRAMS) $(DEP) + +thales-ns4.html: thales.wml $(DIAGRAMS) $(DEP) + +ps: design.ps + +include ../lib.mk \ No newline at end of file diff --git a/Documentation/Clang_Design/design.ptex b/Documentation/Clang_Design/design.ptex new file mode 100644 index 0000000..4610a74 --- /dev/null +++ b/Documentation/Clang_Design/design.ptex @@ -0,0 +1,456 @@ +% BE SURE TO EDIT design.ptex -*- LaTeX -*- +\documentclass{article} + +\usepackage{rcs} +\RCS $Date: 2000/08/19 12:16:43 $ +\RCS $Revision: 1.9 $ +\date{Rev.\RCSRevision~~\RCSDate} + +\title{Clang Design Document} +\author{Tuomas J. Lukka\and Antti-Juhani Kaijanaho} +\begin{document} +\maketitle + +\newcommand{\zz}{ZigZag} + +\section{Introduction} + +.PS +box "Clang" ht 0.25 +.PE +$$\box\graph$$ + +A cellular language, based on the structure of ZigZag has been in Ted Nelson's +plans all along. This document attempts to clarify the various issues in +Clang's design and propose various solutions. + +\subsection{The role of Clang} + +The exact role of Clang in the various uses of \zz\ is still unclear. +The \zz\ system will interface to a wide variety of languages (currently +Java and Perl), and all these can be used to perform various tasks. + +One possible role is as a beginners' language, especially if good visualizations +and ways to write programs in Clang are devised. + +Another possibility is as a kind of device-independent +virtual machine from which code can be compiled to a faster representation +or directly interpreted. + +A further possibility (one being realized right now (Dec.1999)) is a +least-common-denominator scripting language, allowing a simple pure Java +implementation of \zz\ for demonstrations as well as practical use, without +requiring the recipient to set up many libraries and interpreters. + +The ability to record macros directly from user input is a great thing. + +\subsection{Relevant ZigZag features} + +In this section, we shall look at some of the less obvious features +of \zz\ that might be useful. + +\subsubsection{Intersections} + +One of the important operations in ZigZag that is quite relevant +to Clang is the ability to take intersections of ranks. +As an example, this can be used to find an entry at the intersection +of a row and column in a traditional 2-dimensional table. +Of course, as often is with ZigZag, there is a twist: there may be +many different intersection points, since the relationships between +the different ranks are not restricted on a global level. + +For most of Clang we are however only interested in single +intersection points, e.g. to find the value of a given variable in +a give stack frame or the code for a given virtual method in an object. + +Eventually, the server should allow requests to store tables +of intersections so that certain predefined sets of intersections can +be found in $O(1)$ time instead of the most general $O(N+M)$ where $N$ +and $M$ are the lengths of the two ranks (you get $O(N+M)$ instead of +the horrible $O(NM)$ through using a hash table). +However, this is not yet implemented. + +\subsubsection{Clones} + +Clones are quite an interesting concept. Basically, they are just +cells that are on a rank on \texttt{d.clone} with the ``original'' as +the headcell. What is important about clones is the two implications: +the visual and the semantic. The visual implication is that +the rest of the cells will always show the same contents as the +headcell and all modifications are done to the headcell, not the clones. +The semantic implication is more important: it says that the clones +are somehow \emph{same} as the original. + +As with the intersection above, clones can be used e.g.~to clone +method names from an interface to an implementation or something like that. + +But now, the important thing to realize about clones is that they +are special only in these two senses and that we can, if we need +(and we will, as you'll see), define other dimensions with similar +properties. + +\section{Global goals} + +\subsection{Structure-based referencing} + +The most fundamental thing about Clang is that references to various +structures are structure- and not name-based. Thus, a variable is +defined by a cell, which is e.g. cloned along \texttt{d.clone} or some +other suitable dimension to all the places in a subroutine where it +occurs. + +This makes easy many of the functionalities that the so called +Integrated Development Environments (IDEs) work very hard to provide +such as jumping to the definition of a variable or subroutine. +Also, along with some special rasters the structure allows many +useful visualizations of the resulting program structure. + +The question this change raises, of course, is development speed. +Will it be significantly slower to write Clang code than corresponding +Java code? However, some consideration shows this point to be moot: it +is not at all difficult to come up with suitable macros so that Clang +can be \emph{written} like a normal name-based language, but where at +the moment of writing the interpretation to structure takes place. + +\subsection{Compilability} + +Clang code should be relatively easily compilable into a strongly-typed +language such as Java in order to gain execution speed. + +\subsection{Simplicity} + +Ideally, Clang should be simple so that even a beginner is able to write +simple scripts. + +\subsection{Power} + +However, many simple languages lack the power to do complicated things. + +\subsection{Self-implementability} + +To ensure Clang's power as a general-purpose structural language, it should +be possible to completely implement a Clang interpreter using Clang itself. +The only potential problem for this is the dimension along which cell +pointers are used (see Cell pointers below). + + + + + +\section{Interesting ideas} + +\subsection{Visible stack} + +Stack frames can be represented as sets of clones from the local +variables (along a different dimension from the cloning to the references +to the variable in the code). + +Then, the primitive rank-intersection operation in ZigZag can be used +to find the value of a local variable in a stackframe or thread. + +\subsection{Trace} + +A trace of executed code can easily be shown on a dimension, with +relation cells if necessary, along with information about the status +of data at any point. On the other hand, in a fully versioning ZigZag +space the whole history of the state of the space is conserved throughout +the execution (although this may not be wise for complicated scripts +where the space overhead would grow too much -- there only the space being +operated on should be versioned and even that possibly at the beginning +and the end of a script run). + +\subsection{Objects and virtual tables} + +It is delightfully simple to do objects and virtual tables using the +ZigZag structure. + +Quite simply, a virtual interface can be defined simply as a rank of +cells and a type implementing them will have the methods' implementations +start on the intersection of the cell describing the type and the cell +naming the method. + +As an interesting side, since the pointers are bidirectional it is always +possible to find all the instances of a given class or traverse +structures both ways, something that +programmers in more traditional languages would never dream of. +Naturally this comes at a some performance penalty but the coherence +of the structure makes finding bugs in programs far easier. + + + + + + + + + +\section{Questions} + +\subsection{Context} + +How much context should the virtual machine have? +This is an important issue for short scripts +which should be definable with the minimum effort. +Ted says (and I agree) that it should be at least a cursor and three +dimensions (also as cursors), i.e. a viewspex. + +\subsection{Cell pointers} + +A variable should in general hold a pointer to a cell (possibly also +a direct value +but this could just as well be implemented as a temporary cell). + +The problem here is clean self-referencing: how can all the cells involved +in a cell pointer structure be referenced in another cell pointer structure? + +SUGGESTION1: "Local" dimensions? This would lead the ZigZag model closer +to a model of ordered triplets of cells... + +SUGGESTION2: Use the same cursor mechanism (the two dimensions \texttt{d.mycursor} +and \texttt{d.cursor} as the rest of GZigZag). + +\subsection{Parameter passing} + +\subsection{Expressions} + +A rather neat way of doing expressions for parameter passing +to primitives and functions: +the first cell on \texttt{d.1} gives the primitive or function to call. +Then, on \texttt{d.1} come the parameters - either directly \emph{or} if +they are connected along \texttt{d.mycursor}, using cursors (global variables) +\emph{or} if they are connected using \texttt{d.clone} to a parameter cell, +that parameter. + +However, this is only the beginning: from each parameter, you can +start a path down on \texttt{d.2}, which would mean + +\subsection{Exceptions} + + + +\subsection{Typing} + +Typing for Clang is a difficult issue. +On the one hand, Perl-like weak typing would suit the ZigZag paradigm +quite well but on the other hand, compiling a strongly typed program +into e.g. Java is much easier as well as much more efficient. + +SUGGESTION: Have two different languages (Clang and Cling?), one +strongly and one weakly typed. The one we would first define is +the weakly typed one which is generally easier to use for humans. + +POSSIBLE IDEA: Dynamically type cell content in Perl style (assign +dynamically a union of types to a cell based on an analysis of the +content, for example whether the content string can be parsed as a +number), but have statically typed cell references. We'll need here a +powerful type system (look into type theory, Hindley-Milner typing +etc), a Java-like type system would probably kill this idea. + +\section{Extra-primitive Clang} + +XXX This is NOT what is implemented - see the next section!!!! + +This section describes the very first steps taken towards +a cellular language since one is now needed in a hurry to get +a pure Java implementation of \zz\ out soon (Dec.1999) + +This is a testbed-version only and any or all features may be broken +by further versions. Especially the dimensions may be changed (the first +version tries to use as few as possible to facilitate viewing on the +current primitive rasters). +This version has no expressions so it is rather like an assembly +language instead of a scripting language. + +That said, let's begin. + +First of all, we shall have subroutines or procedures. +They are defined by a cell with the name of the subroutine, +which has some cells on {\tt d.args} describing the arguments the +routine requires. The cells on {\tt d.args} will be cloned later +to refer to the arguments (structural reference). +NOTE: there is a potential problem here: we also want to be able +to clone parameter sets for virtual methods and standard routines, +e.g.~for keybindings). Thus, the cloning dimension may change. + +Negwards on {\tt d.args} (later, with better visualizations, on +{\tt d.retval} or somesuch) are the return values of the subroutine. + +The next cell from the main subroutine cell on {\tt d.xeq} is +a clone of the cell {\tt VAR}, introducing the local variables just +like usual languages. + +After this, on {\tt d.xeq} the body of the subroutine follows. +The cell on {\tt d.xeq} is a clone of the operation (or subroutine) +cell and +like above, {\tt d.args} contains the parameters (clones of +the parameter or variable cells) that are given to the operation, +and negwards are the return values. + +\begin{figure} +{ +\tt +.PS +linewid=0.15; +lineht=0.15; +boxwid=0.55; +SUM: box "sum" ht 0.25; line; DIFF: box "diff" same; line; +SH: box "sumdiff" same; line; X: box "x" same; line; Y: box "y" same; +move to SH.s; down; line; box "VAR" same; line; +PLUS: box "+" same; line; +MINUS: box "-" same; +move to PLUS.e; right; line; X2: box "x" same ; line; Y2: box "y" same ; +move to MINUS.e; right; line; X3: box "x" same ; line; Y3: box "y" same ; +move to PLUS.w; left; line; SUM2: box "sum" same; +move to MINUS.w; left; line; DIFF2: box "diff" same; +spline from X.s then down 0.1 right 0.1 then down 0.2 left 0.2 to X2.n; +spline from Y.s then down 0.1 right 0.1 then down 0.2 left 0.2 to Y2.n; +spline from X2.s then down 0.05 right 0.02 to X3.n; +spline from Y2.s then down 0.05 right 0.02 to Y3.n; +spline from SUM.s down 0.1 then right 0.65 down 0.1 to SUM2.n +spline from DIFF.s down 0.3 then left 0.65 down 0.1 then down 0.4 to DIFF2.n +.PE +\box\graph +} +\caption{A simple Clang routine {\tt sumdiff} +that calculates the sum and difference +of two numbers by calling the more primitive {\tt +} and {\tt -} +operations. Horizontally we see {\tt d.args} and vertically {\tt d.xeq}. +The curvy lines indicate clones along {\tt d.clone}.} +\end{figure} + +The model used to store the parameters is, as alluded to above, difficult, +as it will be difficult to accommodate the self-referentiality and +self-implementability. +For the extra-primitive version, we'll just make do with Clang pointers +being ordinary relcells. +Parameters are passed by value. + +\begin{figure} +{ +\tt +.PS +boxht=0.25 +SUM: box "+"; line; X1: box "a"; Y1: box "b"; +move to SUM.s; down; line; +SUMDIFF: box "sumdiff"; move to last box.e; right; +line 0.5; X2: box "x"; Y2: box "y" +move to X1.s ; line to 2/1 of the way between X1.s and X2.s; down; box "Param1"; +move to Y1.s ; line to 2/1 of the way between Y1.s and Y2.s; down; box "Param1"; +.PE +\box\graph +} +\caption{The stack of the virtual machine at the call to the {\tt +} +operation. +We see vertically {\tt d.stack}, horizontally {\tt d.args} +and diagonally {\tt d.clangref}. +Note that the cells {\tt +}, {\tt sumdiff}, {\tt a}, {\tt b}, {\tt x} and +{\tt y} are clones of the cells defining the procedures. +The result cells are not shown, they are referenced the same way +except through {\tt d.clangretref}, in order to allow passing of +variables by reference. +} +\end{figure} + + +\section{Clang1} + +This section describes the first clang, called Clang1 to distinguish. + +The basic concepts are as above: execution down {\tt d.2}, +parameters and formal parameters (prototype) on {\tt d.1}, +parameters by cloning. + +However, there is one important detail which makes programming easier. +This is the concept of ``it'' which is one cell that is in a special +case position. This can later be extended to a stack, if it is felt that +that is appropriate but that might not be quite as helpful (we do not want +FORTH, do we?). Now, this concept is there so that it is simple +to express paths from cells, to be used as expressions. + +Now, all scripts are associated with a viewspecs cell that contains +at least a cursor and usually some dimensions. +The cursor is then equated to the ``it'' so on the main level, moving +``it'' corresponds to moving the cursor (possibly optimized so that the +cursor is moved once, at the end of the script). + +\begin{figure} +\caption{ +An expression as a parameter to an operation. +The main operation is {\tt Op}, the cell we start from is {\tt v}, +and we use a route that takes us to the cell representing the dimension +that the view whose maincell is {\tt v} is showing on the Z axis +(the cursor three steps on {\tt d.dims} from the maincell). +} +{\tt +.PS +box "Op"; arrow; box "v"; +down; move to last box.s; +arrow; +STEP: box "step"; +right; move to STEP.e; +arrow; box "d.dims"; arrow; box "+3"; +.PE +\box\graph +} +\end{figure} + +In the first implementation, to make it as fast as possible to implement +(and to save some space since the current cellscroll does not support +transient cells), the stack is not stored in the structure. This is +unfortunate but since no semantics change, it is quite simple to change +this later. + +As some examples, we'll implement some operations here explicitly in +Fig.~\ref{fig:ops} +\begin{figure} +\caption{\label{fig:ops} +Some operations. a) move poswards on the X axis. b) advance the X dimension +to the next on the X dimlist. c) One possible alternative, allowing the +user to clone "X" only once by expressing the cursor to use negwards on d.1. +In this case, the {\tt SETC} operation would not be necessary at all. +} +{\tt +.PS +STEP:box "STEP"; line; box "X"; line; box "+" +move to STEP.s; line down; +move to STEP.n; line up; +.PE +a)\box\graph\\ +.PS +STEP: box "SETC"; line; box "X"; line; box "X"; +down; move to last box.s; line; box "STEP"; +right; move to last box.e; line; box "d.2"; line; box "+" +move to STEP.s; line down; +move to STEP.n; line up; +.PE +b)\box\graph\\ +.PS +box "X"; line; STEP:box "STEP"; line; box "d.2"; line; box "+" +move to STEP.s; line down; +move to STEP.n; line up; +.PE +c)\box\graph +} +\end{figure} + +\section{Greek Clang} + +My (Antti-Juhani's) intention is to build several parallel prototype +versions of Clang. Since the version of Clang which will be adopted +might well use ideas from several orthogonal Clang prototypes, these +``Greek Clang'' prototypes are not successive versions, improving one +another, but separate parallel ventures into the design space. Thus +they will not be version numbered; instead I'm going to name them +after ancient Greek philosophers. + +\subsection{Thales Clang} + +Thales Clang is a small nonstrict, weakly typed procedural-functional +language with a design in many ways owing to Lisp and nonstrict +functional languages. + +\end{document} + + +% +% vim: set syntax=tex : diff --git a/Documentation/Clang_Design/thales.wml b/Documentation/Clang_Design/thales.wml new file mode 100644 index 0000000..8b6c88f --- /dev/null +++ b/Documentation/Clang_Design/thales.wml @@ -0,0 +1,187 @@ +# -*- HTML -*- + + + +# FIXME + + %body +

%body

+
+ +

%body

+
+ +

%body

+
+ +#include '../wmlinc/article.wml' +Thales Clang Draft Spec +
$Id: thales.wml,v 1.4 2000/09/07 12:34:24 ajk Exp $
+ + + Antti-Juhani Kaijanaho
+ gaia@iki.fi
+ Dept. of Mathematical Information Technology
+ University of Jyväskylä +
+
+ + +

+WARNING! This document is extremely unstable. You +should not depend on any of it to remain as it is. +

+ +Introduction + +

+ +The ZigZag Structure + +

+ +

+The ZigZag structure consists of cells, cell content and connections +between cells along dimensions. Each cell has content (either a +string or a span), and cells are connected along dimensions. +Dimensions have unique names. Dimensions have two directions: the +positive direction and the negative direction. A cell may have at +most one connection along a dimension on a direction. The term +posward means the positive direction and the term +negward means the negative direction; in English text they are +used analoguously to such terms as rightward and upward. A particular +instance of the ZigZag structure is called a ZigZag space. +

+ +Cell references in ZigZag: the cursor mechanism +

+ +Thales Clang Syntax + +

+Thales Clang has six syntactic forms: cell literals, +primitives, cell denoters, applications, +sequences and abstractions. Instances of these +syntactic forms are called expressions. +

+ +

+All expressions have an identity cell, a cell that denotes the +expression as a whole. The identity cell of all expression is a +member of a rank along the dimension d.thales-syntactic-form. +The headcell of that dimension determines the syntactic form of the +expression. An expression can incorporate another expression as a +subexpression by incorporating in its structure a clone of the +subexpression's identity cell. +

+ +Cell literals + +

+A cell literal is a cell that statically represents a cell. It is its +own identity cell. The cell literal refers to the cell in the +structure that it represents, using the cursor mechanism. +

+ +Primitives + +

+A primitive is a cell that represents a primitive operation +implemented outside Thales Clang. It is its own identity cell. +

+ +

+Primitive cells are mapped to their implementations using the +following mechanism. From the home cell, a rank along +d.thales-primitives enumerates all known primitives. Each +primitive cell is connected posward along +d.thales-primitive-binding to a cell whose content is a magic +cookie (a string) used to identify the primitive. +

+ +Cell denoters + +

+A cell denoter is a cell that dynamically represents a cell. It is +its own identity cell. It is an error for a non-clone cell denoter to +appear as a subexpression outside the abstraction parameter list (see +section~). +

+ +Applications + +

+An application expression is a rank of cells along +d.thales-application. The cells in that rank must be identity cells +or clones of identity cells. The identity cell of this expression is +the headcell of the rank. The headcell of the rank must be a clone of +the identity cell of either a primitive expression or an abstraction +expression. +

+ +Sequences + +

+A sequence expression is a rank of cells along +d.thales-sequence. Its identity cell is the headcell of that +rank, and the rest of the cells must be clones of identity cells of +identity cells or identity cells of application expressions. +

+ +Abstractions + +

+An abstraction expression is a subspace generated by the expression +identity cell with respect to the dimensions +d.thales-sequence and d.thales-application. +

+ +

+The rank along d.thales-application from the identity cell +excluding the identity cell itself and the posend cell of the rank +contains a list of formal parameters for this abstraction. The posend +cell of the rank must be an identity cell of another expression, known +as the body of the abstraction. +

+ +Informal semantics + +

+The mechanism by which an application expression whose identity cell +is a clone of a primitive is evaluated is implementation-defined. +

+ +

+An application expression whose identity cell is a clone of the +identity cell of an abstraction is evaluated as follows: +

+ +

+The subexpression denoted by the headcell of the expression rank is +evaluated. The resulting value will be an abstraction. A fresh +environment is created with exactly as many positional slots as the +abstraction value has parameters and one ``inherited environment'' +slot. The environment captured by the resulting abstraction value is +bound to the ``inherited environment'' slot of the fresh environment. +The rest of the cells in the application rank are evaluated in +negative-to-positive order and the results are bound to the +corresponding positional slots. A fresh activation record is created, +and the fresh environment is bound to its environment slot. The +current active activation record is bound to the fresh AR's saved AR +slot. The fresh AR is made current active AR. The body of the +abstraction is now evaluated. The AR in the current active AR's saved +AR slot is made current active AR. The result of this evaluation is +the result value of the body. +

+ + + diff --git a/Documentation/CyberText/1.png b/Documentation/CyberText/1.png new file mode 100644 index 0000000000000000000000000000000000000000..3fef4635b75c904075bb93b2606efae04e252023 GIT binary patch literal 3624 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 literal 0 HcmV?d00001 diff --git a/Documentation/CyberText/3.png b/Documentation/CyberText/3.png new file mode 100644 index 0000000000000000000000000000000000000000..fe0a0307ef92310697abcff5ae8a3a12208b07bd GIT binary patch literal 2527 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 + + + + + GZigZag: a platorm for Hypertext experiments + +#include '../wmlinc/article.wml' + + + + + +

GZigZag: a platorm for Hypertext experiments

+
$Id: ct-old.wml,v 1.1 2000/09/13 14:58:08 tjl Exp $
+ + Tuomas Lukka
+ lukka@iki.fi
+ Dept. of Mathematical Information Technology
+ University of Jyväskylä +
+ Vesa Parkkinen + + Katariina Ervasti + and + Ted Nelson +
+ + + + +

+This is a preprint of an article to appear in the Cybertext Yearbook 2000, +edited by Markku Eskelinen & Raine Koskimaa, to be published by Research Unit +for Contemporary Culture. +All trademarks are the respective trademarks of their owners. + + + + +We present a short summary of the ongoing work at the Hyperstructure Group +in Jyväskylä University. +We are interested in structures that currently dominant software +paradigm makes difficult +or impossible to express or edit. +For example, current operating systems are fixated on files and directories +which could be replaced by a much more flexible and more +fine-grained structural system. +For many applications it would be useful to keep track of where text +has been copied from via cut&paste. The current paradigm does not support +this but e.g. the Xanadu88 paradigm does. +Additionally we are interested in useful visualizations of these structures. + +Most of our work is based on Nelson's ZigZag +structure, and we have a prototype program GZigZag on which various +variations are tried. + + + +

Introduction

+ +

+This article attempts to give an overview of the activities of the +Hyperstructure Group at the University of Jyväskylä. +The group, founded in fall-99 is focused on a long-term collaboration +with Ted Nelson and implementing and testing +his ZigZag design and some Xanadu designs. + +

+The most basic idea +underlying all of our work is that today's computers do not +allow the user to store and visualize most of the real structure of +his information. +An interesting feature of this problem is that it is never visible +on a small scale, with a few documents or files. On a small scale, the human +brain is able to superimpose the true structure of the data on the +structure forced by the computer (filenames and directory hierarchies). + +

+Unfortunately, most software is only tested with small amounts +of example data in the prototype stage. +If there are hundreds of documents, modified by dozens of people, +it is easy to fall into chaos unless the true structure of the data +is used. One simple example of such true structure is that of origination(XXX): +being able to track all text across several cut&paste operations and +visualize this makes it simple to see what rearrangements other people +have done on a piece of text after having seen it last time. + +

+Our work is based on Nelson's ZigZag structure XXXREF, introduced below. +We often use the term ``ZigZag structure''. This is an approximation: +ZigZag is in a sense a metastructure with which it is easy to model any +structure, even structures that would be difficult to model on paper +or on usual computer programs without a special program designed explicitly +for that structure - for example a family tree. + + +

Basics of ZigZag

+ +

+ZigZag is a new way of putting information into computers, kind of a crossing +between a database, a filesystem, a personal information manager and +many others. And even that isn't sufficient to describe it: it's simply +something new. +There are two important differences between systems built on ZigZag +and "normal" computer systems. + +

+First of all, files and directories are unnecessary (REF paradigms). +A traditional filesystem uses filenames to refer to large chunks of +information and possibly HTML-like anchors to refer to smaller pieces +inside the files. This is a fragile way of representing the information +since the only structure stored by the system is the files based +on the names - finding which files reference a given file is timeconsuming +or requires a pre-indexing scheme. +ZigZag is a flexible hyperstructure, allowing different micro-level +connections between various pieces of information. +In ZigZag all references are two-directional and do not work through +user-visible namespaces. Rather, the micro-level two-directional +referencing is built right into the system. Changing some of +the connections of a piece of information (e.g. renaming the "file" it +is inside in the listing) will leave the other connections unchanged. + +

XXXXX +Second, in ZigZag, all +the information about the system will be stored in the same structure. +In Windows, there is a filesystem and separately from it, there is the +registry. In UNIX, there is just the filesystem with configuration +information for applications being represented as text files inside +the same filesystem; same tools can be used to edit normal text files +and configuration files. +ZigZag takes this a step further: all information is in the same fine-grained +structure instead of the coarse "file-grained" structure. +The same tools can be used to edit any part of data on the system, be it +metadata, configuration information, user interface bindings or a spreadsheet +or document. XXX selitä paremmin + +

Cells and dimensions

+ +
+ Two ranks on d.2. The rules of the ZZ structure + are that each cell may only be on one rank along a given dimension. +
+ +
+ Two different ranks involving some of the same cells, on + a different dimension d.1 +
+ +
+ One possible way to flatten the ranks of the two previous + figures to show both dimensions at once. Note how the structure + feels locally spreadsheet-like at each cell but globally + the connections between the cells must curve when flattened + to a 2-D plane. +
+ +

+ In ZigZag, all data is in cells, much like a spreadsheet. + The only important difference is that while a spreadsheet enforces + a two- (or possibly three-) -dimensional lattice structure + between the cells, ZigZag allows the cells to be connected in + a much freer way. + +

+ First of all, the number of dimensions is unlimited. + Like on a spreadsheet, a dimension is still structured so that + each cell may have one predecessor and one successor on each + dimension, and the converse relationship "A is B's successor + implies B is A's predecessor" holds. + However, there are no restrictions between the dimensions + for the connections: for example, in the figure, + the cell A is located two steps right and three steps up + from itself (right = d.1, down = d.2). + +

+ To manage the potentially infinite number of dimensions, + they are referred to with descriptive strings. + The most commonly used dimensions are the three general-purpose + dimensions d.1, + d.2 and d.3 and then d.clone, + used for logical duplication of cells and d.cursor, used + for pointing. These uses are mostly a matter of convention. + +

+ The strength of using dimensions instead of names (as in filenames) + or numbers (as in pointers or references) to refer to other + information is that all references are two-directional. + This is an important feature since a large fraction of programming + errors in languages such as HTML or C++ have to + do with referring to things + that are no longer there: on WWW, moving a page or changing the + name of an anchor on a page breaks all links to that page or anchor, + because the links are strings, naming the previous location. + In C++, the references are pointers, i.e. numbers representing + memory addresses: if the object being referred to is not any + more at the given address, the program crashes. + ZigZag introduces the concept of connection + on a primitive level and obviates the need for making new systems + of referencing for each new program. XXX + +

+ There are many different possible structures with similar + capabilities. What makes ZigZag special is the beautiful tradeoff + between simplicity and complexity: each cell's neighborhood + is limited by the two-neighbours-per-dimension rule but further + away the cells can be connected to each other in a free fashion. + +

Rasters and operations: the default UI

+ +

+ Given the complexity of the structure, it is usually impossible + to see it all at once. Focus&context methods (XXXREF) are + useful for simple visualizations: two or more dimensions are + chosen, and the cells near the user's focus (cursor) are + laid flat on the screen using those dimensions, as far as is + possible within the limits of the structure. Since the structure + locally resembles a spreadsheet, this visualization is extremely + navigable, especially with animation between the motions. + +

+ There are several different possibilities for choosing which cells + to place where, called rastersXXX. + The vanishing raster, for example, renders all cells + up to a given number of steps from the cursor, while + gradually reducing the size of the cells. This gives the user a good + picture of what is happening slightly further along in the structure + and uses the depth perception cues of the human eye to a great + advantage. There are also rasters based on rectangular grids, + with the two most important ones being the vertical and horizontal, + which + Examples of these rasters showing a looping structure are shown in + XXX. + +

+ Motion is performed through the keyboard or the mouse. + Many simple edit operations take directions as parameters, + so for instance, creating a new cell leftwards from the current + cursor is achieved by pressing n and then the same + key that normally moves the cursor left (l). + + +

+ The basic operations include connecting and disconnecting cells, + moving the cursor, rotating the view (choosing different dimensions + to show on the X, Y and Z axes) and modifying the text in a cell. + There are also some more complicated operations that are especially + useful, such as hop, an example of which is shown in XXX. + +

Totality of the structure

+ +

+ Currently, computers are complicated and messy. + Application code has to worry about the structure of data on + disk, the structure of data in memory, and the structure of data + held by the operating and windowing systems. + All these are usually different and cause applications to + translate between each other, making the application overtly + complicated. + +

+ ZigZag represents all this data in the structure: the structure is + persistent and unified. + Just as with virtual memory, + the program does not need to care whether a cell + is in memory or on disk. The logical structure + is the same. Of course, to retain an acceptable level of performance, + solutions such as transient cells or saving only every n + seconds have to be devised but these are optimizations rather + than fundamental structure of the application. + +

+ The unification of the structure is more difficult to explain + since it reflects a completely different mindset from the ordinary. + Ideally, the lower-level code which takes the structure and renders + it on screen will have to know only one cell. + From this cell, it uses the structure to find what windows are + where, which cells to show + in the centers (via d.cursor) and which dimensions + to raster along (also via the structure). + +

+ This greatly simplifies programming in ZigZag since all + operations can be expressed as alterations to the structure. + For example, when the user presses a key to move the cursor left, + what happens is that the callback code looks through the structure + to see which dimension is currently "left-right", then looks + for the cursor and the cell leftwards of it. Finally, the code + connects that cell in the structure so that it will thereafter + be interpreted as the cursor. + +

+ There are many other benefits as well: since all operations + are in the structure, scripting becomes trivial since everything + can be achieved simply through modifying the structure. + +

+ Unification of data is not a new idea: the original + UNIX philosophy of "everything is a file" contains some of the same + spirit. However, the UNIX APIs still force the loading of files + into memory into a different representation; in ZigZag, the cell + structure is all you need. + +

+ Another previous version of the same basic idea is the + popular Model-View-Controller paradigm (XXXREF), where a program + with a user interface is split into a model and + user interfaces (views and controllers) to that model. + This structure makes it simple to add a new view to the same data. + ZigZag takes this approach to new heights by providing a + global model which all features of the visible display + use. + +

Permascrolls

+ +

+ Permascrolls are a concept that originated in Xanadu88 (XXX???). + The essential idea is that whenever a piece of fluid media + (i.e. text, audio, video, image) enters the system, it is assigned + a permanent identifier. After that, all references to that + piece of media go through that identifier so that it is easy to find + where a particular piece of text has been cut&pasted to, for example. + +

+ Permascrolls seem to be the most easily misunderstood part of + Xanadu88 because with today's web, confusing the physical + location and the identity of a document is easy. A permascroll + does not mean that all information should only be + stored in one place. It is not an URL, but more like an URI: it + is an identifier which is known to map to the same information + always. It is also more fine-grained than run-of-the-mill W3C + URIs, as it allows referencing any subset of the original up to + an atomic level. + Most commonly it is not single atoms in the permascroll that + are referred to; rather, the reference type is + span, which is a reference to a single contiguous piece + of a permascroll. + +

XXX SELITÄ VSTREAM HETI + In the permascroll paradigm, a particular version + of a "document" is represented as a vstream: a list + of spans. Editing a document then consists of adding a new + span, splitting existing spans, deleting existing spans and + rearranging spans. + +

+ Two different versions of a document using vstreams + and permascrolls. The second version is produced from the + first by a rearrangement and an insertion. + When comparing the two versions side by side, it is + easy to determine + which parts are the same and simply have been rearranged + by comparing the references to the permascroll. +
+ +

+ ZigZag supports permascolls by allowing a cell to contain + a span (a reference to a single + contiguous piece of the permascroll). + A rank of cells on a dimension (usually d.2) + can then be interpreted + (see next section) as a virtual text (or other media) stream. + +

+ To reiterate, a permascroll is not a place: + it is a state of mind, in which you keep track of what all + information copied or cut&pasted originally was. + For example, it is planned that in a future version of GZigZag + the user will be able to send an email with some cells + as well as the parts of the permascroll that is referred to + by those cells. The recipient's computer can then + store those pieces of the permascroll and notice if any other + references to them exist. + In fact, permascrolls are excellent candidates for caching since + the identifiers to the content are indeed permanent, unlike + on WWW where the content of a cached URL can change at any time. + + +

+ Another application where permascrolls show their power is + comparison: most utilities used for text comparison (e.g. the + unix diff utility) do a reasonably good job if the + user is simply adding or removing or changing small pieces of + text. However, such tools have great troubles with rearrangement, + exactly because of the lacking text model where only the content, + not the origin is stored. Thus, a rearrangement usually shows + up as large insertions and deletions, which is actually exactly + what it is, in the primitive text model. + +

+ It is possible to overcome some of this problem by writing + more and more refined algorithms for finding similar texts but + once we get to phrase-level elements, they become useless since + the same phrases can occur again and again in a document. + +

+ With permascrolls, rearranging a text file is not about moving + the text content - it's about moving pointers to the + content. So two different revisions, the latter of which has + been rearranged, still point to the same spans of text in the + permascroll. Now, visualizing the differences becomes easy: + all that is necessary is to point out to the user which pieces + of text are stored in the same place in the permascroll. + See Figure XXX below, where this is demonstrated. + +

+ This feature may seem like unimportant but in projects with more + than one worker and much rearrangement of the manuscript + it can be truly invaluable for finding where a certain part of the + previous version of the manuscript ended up. + +

Alternative visualizations: applitudes

+ +

+ Although interesting, the above structure and visualizations + would fit most applications rather poorly. However, given the + basic ZZ structure it is simple to define new visualizations. + +

+ Taken together, a visualization and operations are referred + to as an applitude, + as opposed to the traditional term application + since all the data is still in the same structure and other + operations can be used to edit this data and these operations + can be used to edit other data. + +

+ For example, a vstream is a kind of an applitude: there is a + clearly defined internal structure and special operations for + the vstream for inserting and deleting characters. + There is also a good visualization of a text vstream: simply + the characters in a paragraph (formatting capabilities will + be added later). + The default cell-based visualization and the natural vstream + visualization for a small piece of text is shown in XXX. + Note how the colored cursor is shown in both panes. + +

+ The interesting thing about applitudes is that they can be designed + to be connected to each other in a more fine-grained fashion than + current embedding frameworks such as Bonobo, KParts, or OLE/COM. + + + + +

Some Textual Applitudes of ZigZag

+ +

+In this section, we'll look at some functioning applitudes. +As explained in the previous section, the strength of ZigZag lies in that +all these applitudes can be used together fairly easily since all the data +is stored openly in the ZZ structure. + +

+One important function that GZigZag provides for all applitudes is +animation. This works by associating a cell with all "things" +that are rendered on the screen. +When two "things" in subsequent keyframes (i.e. the fully rastered frames) +are associated with each other, the system generates as many interpolated +frames between them as the speed of the host machine allows. +The time between keyframes is estimated from the interval between +the user's keystrokes: the system attempts to be ready 100ms before +the user strikes the next key. This gives the system a fluid, responsive +feel while allowing smooth, slow animation if the user is moving slower. + +

+An example of such animation can be found in XXX ANIMATED GIF ON +GZIGZAG PAGES + +

Text cloud - real cut&paste

+ +

+ One of the points Nelson has made in several talks (XXX??? on paper?) + is that the term "cut&paste", as used in the computer field, is + a really bad choice of words. Originally cut&paste meant physically + cutting a text into pieces, rearranging the pieces and glueing + them together. This seems a little similar to what the computers + do. + +

+ However, there is a crucial difference: in physical cut&paste, + the text can be cut up into as many pieces as desired; + all the pieces are visible all the time; the pieces can be slowly + rearranged into the optimum order in a parallel fashion. + Indeed, when the text is cut up, the actual data model + of the text + is changed from the single text stream to a cloud of text + fragments. + +

+ Most current computer programs (XXX Exceptions?) force the user + to stay within the formal one-stream text model all the time during + editing, except for a single piece of text cut onto the "clipboard", + which is not seen. + This is why several people (REF: private communication) seem + to use a second window next to the main one to hold fragments. + This, of course, has several disadvantages: the fragments are + stored separately from the main body of text, the fragments still + have to be stored in the one-stream text model and the system is + rather clumsy. Of course, some people are able to write near-perfect + prose in near-perfect order. + +

+ One of the interesting differences between this system + and the dominant paradigm is the way of selecting text. + In most current systems, selecting text is performed by + painting, i.e. pressing the mouse button at one end of the + span being selected and releasing the mouse button at + the other end. In the TextCloud demo, text is never really + "selected" in the same way: instead, the user can make any + number of cuts into the document using the right + mouse button. Then, when the user presses the left mouse button + on some text and drags, the text is separated at the neighbouring + cuts to allow the user move a single piece of text. + +

+ Already Nelson's original mockup pictures about Xanadu + (see XXX (pic on WWW)) + include transpointing windows, i.e. windows which show the + connections of their respective contents graphically. + These connections can be either transclusions or links. In this + article, we concentrate on transclusions. + +

+ GZigZag is probably (XXX???) the first system to implement such + transpointing with beams: an earlier Xanadu client Pyxi by XXX + shows transclusions by colors but does not do transpointing. + The TextCloud applitude is a good place to see the transpointing beams + in action: simply copying (i.e. dragging with Shift-MouseButton1 instead + of just MouseButton1) a vstream creates a transclusion and the + beam appears. Then, when editing one (or both) of the streams by + cutting&pasting text the beams remain + connected; this is because the beams are really connected to the actual + text content, not just the external object. + +

+ The TextCloud is a simple model and its current implementation clear + limitations: all text must be stored in this one area and the size + of the text cannot be changed. + Also, it does not interface well with the other parts of the system. + It is simply one step on the way towards the full system, in order + to test one user interface aspect of it. + + +

Editing longer documents using cells

+ +

+ A different way for editing longer documents is through putting + vstream fragments of the documents in ZZ cells which are then rendered + in a raster. All the structural capabilities of ZigZag are + then in use for rearranging the pieces. + +

+ This being ZigZag, note that "putting fragments in ZZ cells" + does not a literal inclusion but an interpreted inclusion: + the view has a special raster which knows how to look for + the vstream to include in a cell. + When the space is being rastered, + +

+ Unfortunately this demo is not yet finished so we cannot offer + a screenshot. + +

Hypertext without lexias (XXX?)

+ +

+ Hypertext has come to mean "WWW-like" in many places: + a paradigm where the user is presented with one lexiXXX, + performs a selection, for example clicking with the mouse, + and is taken to another lexiXXX. + +

+ GZigZag makes it possible to easily create a wealth of flexible + visualizations that do not use such fixed screenfuls of text. + This is because GZigZag is built in a modular fashion and makes + it easy to describe a new visualization. + +

+ For example, let's start with a text model that contains + simply paragraphs of text, one after another. + + +

Email or forums with coordinates

+ +

+ In this section, we come once again to a problem which + does not exist for small data sets. If there are + only 10 messages in + a mailbox, it does not matter in the least how incredibly + bad the mail reading program is: + humans can still manage since they can remember + and overlay the true structure on top of the rigid and unnatural + structure imposed + by the mail reader program. + +

+ However, consider the linux-kernel email list or + corresponding high-volume newsgroups on the usenet. + Most programs for reading news or email are based on the assumption + that the reader wants to read all or most of the incoming messages - + a natural assumption stemming from the original volume of the forums. + However, with time the number of messages in a forum has grown + unmanageably yet programs mostly offer only rigid pre-selection systems + such as killfiles which remove all messages with a given subject + or sender from the view. + + +

+ ZigZag and FloatingWorld provide an interesting alternative + which we have so far had time to only scratch the surface of. + When a mailbox or a newsgroup is incorporated into the structure + correctly, it is simple to write interesting visualizations + that show some of the emails. + +

+ The structure underlying the email applitude is described in + FIGUREXXX. + +

+ The first, simplest visualization FIGUREXXX + is simply the traditional + mailbox visualization, offered by many programs such as Pine, XXX. + This simply shows some of the most relevant header fields of + messages on each line, arranged vertically in the mailbox order. + Already here ZigZag has several tricks up its sleeve. For example, + a message may be stored in several "folders" (lists), either + by using different dimensions for different folders or by + cloning the headcell of the + message onto different ranks on the same dimension. + Another trick here is that it is easy to see which folders + a given message has been connected to, since all connections are + two-directional. This is an advantage caused by the fact that ZZ + considers the message to be an entity rather than a stream of + characters that can be copied but has no identity + (like emails in normal email folder files). + +

+ Sorting the emails is of course possible, either by presorting + and making a rank of them and using that + or by post-sorting at each time they are shown. + For sorting, ZZ offers an interesting user interface: when the + user moves the active cell horizontally, the list of + mails is shown sorted according to that cell. + XXX Mailboxes, many folders per email!!!!! + XXX Good argument for postsorting or cached postsorting. + XXX Notifications + +

+ +

+ Now, one interesting thing that ZZ offers is multiple windows + with different views whose cursors are bound together (using + the cursor-cargo mechanism; see the ZZ Spec XXXREF). + All the views above have one "active" cell. We can have several + useful views visible at the same time, which stay in lockstep with + each other. + + + +

+ The FloatingWorld model offers an alternative: messages + or icons of messages can be shown in a two- or three-dimensional + coordinate system. + +

+ Such a system is trivial to implement in a general fashion + using ZigZag since the homogeneous structure makes it simple + to specify paths to obtain coordinates through, whereas if + using a traditional programming language, it would be all too easy + to restrict the world of possible coordinates to some set + that is easily specifiable in the structure that was chosen. + +

+ Additionally, normal email programs or HyperMail (XXXREF) + -like HTML indexers treat the messages as their own, making it + almost impossible to link the discussions into the places where + they would belong: for example, linking the discussion leading up + to a particular decision in a standard (say XHTML) into the place + in the standard would be an invaluable aid to those trying to + understand afterwards how something is supposed to work. + +

+ Consider, for instance, a document such as the Kernel Traffic + weekly newsletter (XXXREF) which summarizes the main discussion threads + on the Linux-Kernel mailing list that week. + + XXX transclusions, etc. + +

Editing hyperliterature with nodes

+

+ - editing trad. hyperliterature easier: visualize the STRUCTURE of + the whole work, then rendered into HTML + +

Scientific publishing using Xanadu hypertext

+ +

+ A long-known problem in scientific publishing on paper media is + that bibliographic references are always backwards in time, while + it would often be more interesting for the reader to + know the future references, i.e. either articles that refer + to the current one or articles that the author has deemed + interesting enough to refer to at a later date from publication. + +

+ Now, in the Xanadu model, quoting is equivalent to linking because + of transclusions. + +

+ Transclusions may seem foreign as an instrument of quoting and + responding to a selected portion of an article. However, they + are actually quite close to another widely used paradigm: quoting + when replying to an email. The only addition here is that + the quoted parts (which are somehow visually indicated) are + not copies but transclusions from the original article. Because of + this, they are actively connected to the originals in an implicit + two-way link. + +

+ The system of moderation used on sites such as slashdot.org + is surprisingly similar to the scientific refereeing process. + The privilege of moderating other users' comments is granted + to established members of the community (members whose previous + moderations have been approved by other members), the process + is anonymous and determines on whether users get to see the comment. + However, there are important differences: +

    +
  • The moderation is not "accept/reject" but rather + "leave as is/ increase score/ decrease score". +
  • Comments are not deleted even if they have a low score; + users browsing the site can set their comment limit + themselves to determine what minimum rating for comments + they wish to see. +
  • A user has a default score based on his/her earlier + success in posting comments +
  • Comments are usually short notices on +
+ Upon consideration, some of these points are quite applicable + to scientific publishing as well. Specifically, the "letters + to the editor" section of scientific journals seems to be the + closest that print journals can come to this kind of convenience. + +

+ Indeed, this sort of publishing system could create a far more + interactive scientific discourse. + For example, a user can choose which links he wishes to see + when reading an article: refereed links, all links, links by certain + persons etc. + + + + +

The Code

+ +

+GZigZag, which is the program that is shown in all of the screenshots +in this article, is free software. It is distributed under the FSF's +Lesser General Public License (LGPL) and is available on SourceForge. + +In the language of the free software community, "Patches accepted". + +

Conclusions

+

+ +

Acknowledgements

+

+ +

References

+

+http://www.acm.org/cacm/AUG96/antimac.htm + +

Glossary

+ +

+This article uses many terms that are most likely unfamiliar to the reader. +We attempt to summarize the most important ones below. + +


+
+
ZigZag structure / space +
A simple structure, based on cells and dimensions + which the user is able to easily shape into any desired + structure. All interrelated pieces of information can be + close to each other on some dimension. +
cell +
The smallest unit of information in ZigZag. + A cell can contain a text string or + a single span in a permascroll; the separation is + because a text string can be edited but a span can only + be lengthened or shortened: no characters can be + inserted. Cells are connected to each other along + dimensions. +
dimension +
Connecting cells along dimensions is what ZigZag is + about. Locally, dimensions work just like on a spreadsheet: + each cell can be connected to one cell in the positive + direction and to one cell in the negative direction + along each dimension. However, there are no global constraints + between the dimensions. + +
rank +
A rank on a dimension D is simply a set of cells that are + connected to each other on D. A given cell can only + be on one rank on a given dimension. + +
raster +
A simple visualization of the ZZ structure. + A raster is given a cell to place in the center of + the view and a set of dimensions chosen for the coordinate + axes X, Y and possibly Z, and it starts at the center cell + and places other cells on the screen according to simple + rules. + There are several different rasters. +
+
+
+ +
FloatingWorld +
Ted Nelson's design built on top of ZigZag structure, + based on flobs. +
flob +
A multi-dimensional flying object. That is, an entity + representing something that may have any number of + flob coordinates. For example, an email's sender is one + flob coordinate, its subject another. + +
+
+
+ + +
Xanadu88 +
A hypertext system, finished in 1988, which works by + stable fluid media content instead of URL-like pointers. +
fluid media +
Any media types that can be subdivided. + Text, audio, video, images. +
permascroll +
A storage philosophy for fluid media where + each smallest unit (e.g. character of text) + is assigned a permanent identifier when + it first enters the system. Of course, + references to the smallest units usually happen + through spans for efficiency. +
span +
A (reference to a) contiguous section of the permascroll. +
vstream +
A list of spans that describe a virtual stream of + fluid media. A "document" or one version of a document. + Modifying a document does not modify the permascroll, except + by appending new inserted characters. Instead, the spans + of the vstream are modified: split apart, new spans + inserted etc. +
transclusion +
The inclusion of the same material in a permascroll in + two different documents. One of the fundamentals of the Xanadu88 + model is that it is efficient to search for transclusions + of a given span. +
transpointing windows +
Windows on a computer screen that show the connections or + transclusions between each other. + +
+ +

SCRATCH

+ +

+ +This section contains rejected pieces of text that may still +have some interest. + +

+ Naturally, if desired, dimensions can be used to construct + systems analogous to files and directories: for instance, + a number of cells going down d.2 can contain names + and these cells are connected on some dimension to the content + for that "file". + +

+ This is somewhat analogous + to the hyperbolic visualization + for graphs (XXXREF): hyperbolic space also looks locally like + Euclidean space but there is more "room" because the correspondence + to Euclidean space does not hold over distances. + An interesting similarity between the two is the volume of balls: + in hyperbolic space, the volume enclosed in a ball grows exponentially + with the radius and the same is true for ZigZag - if + desired; ZigZag cells can also be arranged in a less complex + fashion where the growth of the volume of balls is more restricted. + +


+
+ + + + + diff --git a/Documentation/CyberText/ct.wml b/Documentation/CyberText/ct.wml new file mode 100644 index 0000000..10bf472 --- /dev/null +++ b/Documentation/CyberText/ct.wml @@ -0,0 +1,275 @@ + + + +GZigZag - A Platform for Cybertext Experiments + + + +
+

+GZigZag - A Platform for Cybertext Experiments
+Tuomas Lukka & Katariina Ervasti +

+ +

ABSTRACT

+ +

This article describes GZigZag, which is currently the main project of the Hyperstructure Group +at the univ. of Jyväskylä. GZigZag is an implemention of ZigZag, a computer paradigm invented +by Ted Nelson. The paradigm abandons many currently central concepts, such as folders, files and +applications, and instead offers a more flexible way to arrange information. Already at this early stage +of development GZigZag has advantages compared with other computer systems.

+ +

1. INTRODUCTION

+ +

"COMPUTERS ARE FUNDAMENTALLY BROKEN" lectures Ted Nelson (7 February 2000). Unlike +many other critics, he also offers ideas for improving the situation. Some of his ideas are +currently being implemented by the Hyperstructure Group at the university of Jyväskylä, Finland. +In this article we present a short summary of our ongoing work.

+ +

1.1 Defamiliarization of files, folders and applications

+ +

Nelson (1999a) offers many reasons for why users face difficulties with present PCs. This article +only includes a short attempt to defamiliarize (1) folders, applications and files from the user's point of view. +This is not an easy task, because folders, applications and files are one of the first things a beginner +is taught and are not often questioned.

+ +

Hierarchical directories, also referred to as 'folders', were invented to help finding the right file +among many files (Nelson 1999a). Let us say that in September -99 a writer has been writing an +article dealing with the impossible nature of her cat Vilma. In September 2000 she wants to find the +article again to edit it for a new purpose. In order to find the article, she opens a folder named 'Vilma'. +The folder includes approximately twenty files, which are either versions of the final article or include +some ideas the writer has considered worth writing down at some point of the writing process. The +files have names such as vilma3.doc, vilma4.doc, vilfoo.doc and vilmaprob.doc. By the time the +writer finished the article she had no time to make an index explaining the contents of each file. Finally, +after opening and closing several files, she succeeds in finding the right file and starts working. When +editing, she suddenly remembers that she had a slightly different version of a paragraph in another +document. Once again, she has to start opening and closing files to find the right file.

+ +

Applications, then, are used for performing different tasks with the computer (Nelson 1999a). Problems +arise when a user wants to use the same information in many applications. For example, a multimedia +author, who has manipulated sound with SoundEdit, might want to use the sound in a multimedia +presentation made with Macromedia Director. Since applications do not support all file formats, +he has to find out which sound file formats Macromedia Director supports. After a study of sound +file formats, he saves the file in a suitable format and imports it to Macromedia Director. Then, if he +later views the presentation and wants to find a different sound sample, which he remembers recording +in the same session, it will not be easy. This is because there is simply no connection between +the Macromedia Director file and the original sound sample nor between the original sound sample +and the second sample from the same session.

+ +

These examples demonstrate how the files and folders model of storing information is insufficient: +it does not allow the users to track the conceptual relationships between related information or +versions. Files, folders and applications are easy to understand but do not need to be, as +Nelson (lecture, 30 August 2000) explains, fundamental concepts of software. The above +problems could be solved by designing software differently, starting from different assumptions.

+ +

1.2 Traditions of Bush and Engelbart

+ +

Vannevar Bush and Douglas Engelbart developed ideas for tools that would improve the +working conditions of people who perform complicated tasks in the complicated world. Bush, who +had noticed the explosion of information already in the 1940's, is famous for proposing Memex, +a "mechanized private file and library" designed to help individual scientists store and handle the +growing amounts of information needed in their work (Bush 1945). Engelbart, the developer of NLS, +a tool for collaborative work, writes about augmentation of man's intellect, which has been the goal +of his work with computers. By augmenting man's intellect he means "increasing the capability +of a man to approach a complex problem situation, gain comprehension to suit his particular +needs and to derive solutions to problems" (Engelbart 1962). The purpose of our work is similar +to Bush's and Engelbart's: we want to facilitate the production and arrangement of information +by creating, as Nelson (1999b) expresses it, "a high-power personal and media system, with editing +and presentation systems that expand the state of art".

+ +

2. BASICS OF ZIGZAG

+ +

Defining ZigZag is difficult, because ZigZag is so different from any software in the currently +dominant computer paradigm. It is not an application but neither is it an operating system or +a platform. It is a new way of putting information into computers, a cross between a database, +a filesystem, a personal information manager and many others, and even that is not sufficient +to describe it. ZigZag is simply something new and different.

+ +

3.1.1 Cells, Dimensions, Views and Applitudes

+ +

A ZigZag structure consists of cells and dimensions. A cell is the basic unit of information +in ZigZag. A cell can contain an information unit of any kind, for example text (e.g. "Vilma"), an +image (e.g. a picture of Vilma) or sound (e.g. "Meow" by Vilma). Cells can be connected with +each other along dimensions, which are referred to with names such as d.1 or d.cursor. On +each dimension, each cell can have two neighbours: a predecessor and a successor. The number +of dimensions is not restricted, and it is easy to create new dimensions. For example, if Ville wants +to comment on many different cells, he could use d.Ville-comment for connecting his comments +to the cells.

+ +

Figure 1 shows a simple structure. In the Figure, cells are represented by rectangles and neighbours +along a dimension by a line.

+ +

Figure 1.Seven cells, connected to each other along the two dimensions d.1 and d.2

+ +

There are several different visualizations (views) of the ZigZag structure. The views range from +general views that are useful for looking at all kinds of structures to specific views +that are useful for only one particular kind of structure. For example, Fig. 2 shows a generic view of a structure +that represents a schedule of a day. This view can show any kind of structure in a fairly reasonable +way, by showing the cells arranged along the dimensions and their text contents.

+ +

Figure 2.The most important events of a day in a general view

+ +

Figure 3, then, shows a specific view of the same structure. The underlying data is exactly the +same, but the specific view designed especially for the purpose interprets the structure and draws +the events in a more visual manner. Looking at another structure through this view would not make +sense because the view is designed especially for this structure.

+ +

Figure 3.The same events in a specific view

+ +

Combining the specific view such as the schedule view above with special operations for editing +such a structure, for example dragging the start and end times with the mouse makes an applitude. +Thus, an applitude consists of views and operations designed for a particular purpose. Even though +the term 'applitude' resembles the term 'application', there is an important difference: in ZigZag +nothing is separate, and applitudes, unlike applications, can be combined with each other, as the +example of the next section shows.

+ +

3.1.2 Example: Address Book and Family Tree in GZigZag

+ +

One of the first examples Nelson (pers.com., 25 August 2000) has used to demonstrate +ZigZag is the Holm Family Demo, a family tree prepared for his talk at the University of Oslo +to show how he is related to one of the professors of the university. Here, a variant of Nelson's +original example is used, combined with an address book.

+ +

The structure of the address book is simple: it is a list of names and addresses . The names are +listed along d.2 in alphabetical order. The addresses are connected to the names along d.1. +Figure 4 shows the (incomplete) address book in the row view.

+ +

Figure 4. The address book in the row view.

+ +

Since the list of relatives is long, only a subset of it can be seen on the screen at a time. In Figure 4 +the cursor is on the cell 'cousin 1'. Moving the cursor down would cause more cells below +the 'grandfather 2' cell on d.2 to become visible.

+ +

Next, the address book is combined with the family tree, which is represented by a slightly more +complicated structure, shown in Figure 3.

+ +

Figure 5. One family of the family tree in the row view

+ +

The two dimensions d.marriage and d.children are used to represent the family tree. Siblings +are connected along d.children, and married couples along d.marriage (2). An extra cell ("+") is used +on d.marriage to make the structure symmetric, and the list of children from the marriage on +d.children starts from that cell. Figures 5 and 6 show two different views of the structure. +The row view, as Figure 5 shows, enables dealing with one family at a time. The vanishing +view shown in Figure 6 gives a better picture of the family tree as a whole.

+ +

Figure 6. The family tree in the vanishing view + +

It is important to realize that the same cells are used to represent the relatives in both the +address book and the family tree, and that the connections related to the two applitudes are +along different dimensions. In the default views only two or three dimensions (x,y,z) can be +shown at the screen at a time. As it can be seen on Figure 4, the dimensions used for viewing +the address book are x=d.1 and y=d.2. Rotating the dimensions to +x=d.marriage and y=d.children shows the family tree, as in Figure 5.

+ +

The address book and the family tree could be combined with further applitudes. For example, +a cell representing a person could also be connected to photographs and emails having to do +with that person. Simply all related information could be connected so that it is easily accessible. +A consequence of the ZigZag structure is that all connections are two-directional, which means +that navigating between related information is easy.

+ +

3.2 Utility of GZigZag

+ +

ZigZag offers several advantages compared with existing computer systems. To begin with, as Nelson (pers.com., 25 August 2000) usually +remarks after showing his Holm Family Demo, "we did not create a genealogy program". Modeling a complicated structure such as the family +tree on usual computer systems would require creating a specific program for that purpose. Modeling a complicated structure using +GZigZag requires only creating of new cells and connecting them along dimensions.

+ +

Remarkably, there are no separate files and applications in ZigZag. As seen above, the same +cells can simultaneously be part of different structures without any restrictive boundaries. +Thus, a multimedia author using GZigZag would not have the same problem as the multimedia +author described in 2.1. Connecting the same cells in various structures also facilitates updating +information. Updating the last name of a newly married aunt in the family tree and address book +requires updating only one cell.

+ +

In addition to this, ZigZag is a more flexible way to arrange information than the conventional +files and folders model. A certain piece of information is found by following the connections +that the user has previously made based on his associations. Hence, a user of GZigZag does +not need to remember file names in order to find the right information. The writer looking for +a document containing an interesting paragraph about Vilma (described in 2.1) could simply +follow a connection made previously. Also, moving between different versions of the same +paragraph is simple when using the Xanadu content model.

+ +

Finally, ZigZag separates the structure and visualization of information. This is somewhat +similar to HTML 4.0 and CSS, but ZigZag generalizes this: all structures and all visualizations +are possible. The same GZigZag structure can be used in different media from mobile +phones to the immersive virtual reality of the CAVE, because different visualizations +can be constructed to take full advantage of each medium.

+ +

3. CONCLUSION AND FUTURE WORK

+ +

The primary purpose of this article, which is the first publication of the Hyperstructure Group, +is to present a short summary of our ongoing work, especially GZigZag. This is not a simple +task because we are dealing with such a different view of the computer. Indeed, the difficulty +of explaining the new ideas to people has been one of the main problems of Nelson's broader +Xanadu project.

+ +

In the near future we are focused on developing a stable, working GZigZag on the Java +platform and cellular language Clang, which would make programming easier. We are also +planning a network protocol for exchanging cells between computers +and developing applitudes for several purposes in order to learn more about the system.

+ +

We believe that Nelson's ideas are creative, excellent, original and that they should finally be +understood and implemented. Our long-term goal is to develop a computer system we would +like to use ourselves. ;-)

+ +

Everyone interested in our project is welcome to test and work on the current version of GZigZag, +which can be downloaded from the project's homepage. GZigZag is a free software project: the +source code is released under the LGPL license and interested parties are welcome to join +our mailing list. By the time this article is published, we hope to have released the first stable +version (recommended for non-developers). "Patches", as people of the free software +community say, and any other ideas of developing the system are gladly accepted.

+ +

ACKNOWLEDGEMENTS

+ +

We would like to thank Theodor Holm Nelson and Marlene Mallicoat for our collaboration. +We would also like to thank the other members of the Hyperstructure Group: Tuukka Hastrup, +Antti-Juhani Kaijanaho and Vesa Parkkinen.

+ +

FOOTNOTES

+ +

1 According to Fowler (1986: 35, 42) defamiliarization is the use of a strategy to force us to look at familiar things in a critical way, to see the +absurdity of a familiar object. Criticism, as Fowler sees it, is not a negative practice. The basic motivation for criticism is "healthily sceptical +inquisitiveness", which can give a stimulus to developing things for better (Fowler 1986: 34).

+ +

2 If a person has been married several times, a mechanism called cloning is used to represent this in the structure. However, +this is beyond the scope of this article.

+ +

REFERENCES

+ +

Print References

+ +

Fowler, Roger (1986). Linguistic Criticism. Oxford: Oxford University Press.

+ +

Electronic References

+ +

Bush, Vannevar (1945). As We May Think.
+Available in the Internet: +http://www.theatlantic.com/unbound/flashbks/computer/bushf.htm

+ +

Engelbart, Douglas (1962). Augmenting Human Intellect: A Conceptual Framework.
+Available in the Internet: +http://www.histech.rwth-aachen.de/www/quellen/engelbart/ahi62index.html

+ +

Nelson, Ted (1999a). Ted Nelson's Computer Paradigm, Expressed as One-Liners.
+Available in the Internet: +http://www.sfc.keio.ac.jp/~ted/TN/WRITINGS/TCOMPARADIGM/tedCompOneLiners.html

+ +

Nelson, Ted (1999b). ZX Views.
+Available in the Internet: +http://www.xanadu.com/FW99/ZXviews.html

+ +

Other References + +

Nelson, Ted. Lectures at the University of Jyväskylä. 7 February 2000 & 30 August 2000.

+ +

Nelson, Ted. Conversation with the authors. 25 August 2000.

+ +
+ + + + + + + diff --git a/Documentation/CyberText/email.dia b/Documentation/CyberText/email.dia new file mode 100644 index 0000000000000000000000000000000000000000..163cb9eff08a026dd790ad379b48a7a6dbdb58a9 GIT binary patch literal 3332 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 OdiQ_D77dZQ0097$q-#|G literal 0 HcmV?d00001 diff --git a/Documentation/CyberText/kello-o.png b/Documentation/CyberText/kello-o.png new file mode 100644 index 0000000000000000000000000000000000000000..be3d832b333f7e875598b9c599f88d9b94153dfc GIT binary patch literal 14124 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 BeY^kw literal 0 HcmV?d00001 diff --git a/Documentation/CyberText/rank1vert.dia b/Documentation/CyberText/rank1vert.dia new file mode 100644 index 0000000..6c5ba05 --- /dev/null +++ b/Documentation/CyberText/rank1vert.dia @@ -0,0 +1,601 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #A# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #B# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #C# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #E# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #F# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.2# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #G# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #H# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #I# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #J# + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/CyberText/rank2vert.dia b/Documentation/CyberText/rank2vert.dia new file mode 100644 index 0000000..f847b51 --- /dev/null +++ b/Documentation/CyberText/rank2vert.dia @@ -0,0 +1,375 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #A# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #G# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #F# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #J# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D# + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/CyberText/rank3both.dia b/Documentation/CyberText/rank3both.dia new file mode 100644 index 0000000..7507be8 --- /dev/null +++ b/Documentation/CyberText/rank3both.dia @@ -0,0 +1,745 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #A# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #B# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #C# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #G# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #H# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #I# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #E# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #F# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #J# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.2# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/CyberText/vilma.png b/Documentation/CyberText/vilma.png new file mode 100644 index 0000000000000000000000000000000000000000..20a0e427fe09e7eacc98d3f0e825be5e2db6e090 GIT binary patch literal 3377 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 Hu0mjfX^(9O literal 0 HcmV?d00001 diff --git a/Documentation/DesignProblems/Makefile b/Documentation/DesignProblems/Makefile new file mode 100644 index 0000000..850da15 --- /dev/null +++ b/Documentation/DesignProblems/Makefile @@ -0,0 +1,11 @@ +DIAGRAMS=linkorder.png beamorder.png + +all : dp.html dp-ns4.html + +dp.html: dp.wml $(DIAGRAMS) + +dp-ns4.html: dp.wml $(DIAGRAMS) + +include ../lib.mk + + diff --git a/Documentation/DesignProblems/beamorder.dia b/Documentation/DesignProblems/beamorder.dia new file mode 100644 index 0000000000000000000000000000000000000000..af40a463e0cc6d7313eb2c139625d1819cadd6c5 GIT binary patch literal 743 zcmVoX82(tz;z zYoTt12%mL*zu#;4$bq0t!zj`?)PDhtfi8`7bvaO!a{vzr5YJ_^KnRB1NI->v04`J) ztbh89M#NK7tITdqF=fgQ;DtKeB#)|RFnR&!0(J;O$jY!mNI8-w;uuy;8gSzA%qFwq z(unxW;b&)ACW2#g8-+2u(YZ59)*t+xP24gz6n_01c<~vThFK`jvY5I*;96w)`Aq=g0p=;6ls9@%^HOD~3i1}}SEHEUI zBkM`<_sA35>YCnV*~RrOME+JZW4CmhZ|Qzj(?+hRZG9)va}l;yrP)=LcCVtePMVzF zLz4DGk$+v0R#!zjBd142+OZ zGJEupJNA(8@E~e5>2%ekEbP5Dk;!yAax}}B%;po#HZ9pl;*WNmA`U{Om=*62N;XYD zGr1Wk*p)63;(#|?BV0KCH5~vc5p`tod}i{6MhwY>)4T9gq<`%k`*Dh*oUTf$4Mn+W z)iy38dAbqFGrvy)SpRSG?s99yYLDi + + + + + The major internal design problems left in GZigZag +#include '../wmlinc/article.wml' + + +{: [[s/(?)(d\.+\w+)/\1<\/code>/g]] +

The major internal design problems left in GZigZag

+
$Id: dp.wml,v 1.14 2000/08/15 05:19:18 tjl Exp $
+ + Tuomas Lukka
+ lukka@iki.fi
+ Dept. of Mathematical Information Technology
+ University of Jyväskylä +
+
+ + + + + +

+This is a short exposition of the design problems currently in ZigZag +(as of June 2000). The intent is to eventually evolve this into an exposition +of the internal design of GZigZag, after the problems are solved. But +at the moment most of the problems still exist. + + + +

Introduction

+ +

+ This document is intended as an internal discussion document + on the most difficult design problems for the GZigZag source code. + This is work-in-progress: if there are any unclear parts, feel + free to ask me to clarify things. + +

Device-independent Floating Graphics

+ +

FloatingWorld Graphics

+ +

+ The FloatingWorld graphics model built on top of ZigZag is based + on flexibly plotting objects defined by cells on the screen. + ZigZag rasters are simply a special case of this: the coordinates + are given by hopping along ZigZag ranks and the objects rendered + are simply the cells and the texts inside them. + +

+ Conceptually, there are two kinds of objects shown on the + screen: flobs and relations. Also, there are three + different processes in the background: where are flobs + rendered, what kind of flobs are rendered and what + relationships between them should be shown. All these are + relatively independent of each other and should be clearly + decoupled in the backend. + +

+ Animation has been supported from very early on in GZigZag with + excellent results: the human eye can use the motion to understand + the relation of the different views in time much better than + if the views are just switched without the intermediate frames. + This feature should be global: if the same object is shown in two + consequent views, it should animate from the previous view to the + next to show the deep relationship between the two appearances. + Even a simple linear interpolation, without any regard to the + true structure of the transformation between the two views is + astonishingly helpful. It is easy to see that animation mostly + concerns the flobs which must interpolate their coordinates frame + by frame between rasters. In fact, currently the links are not + shown when animating; this does not appear to be a significant + problem to the human observer: maintaining a high frame rate is + much more important than giving a complete picture. + +

+ In addition to animation, depth perception of the human eye + is misused in the vanishing raster to a great advantage: cells + further away from the cursor are shown smaller and grayer and + are rendered behind the cells closer to the cursor. I term this a + misuse since there is no 3D model behind: it's just an algorithm + that lays out cells that happen to look smaller and grayer and + thus further away. + +

The desired level of generality

+ + We shall take four views as an example of the generality the system + has to offer. +
    +
  • + Normal, box-and-stick view (loose-brick) +
  • + Tight-brick view: the cells are drawn right next to each + other. The line drawn between the cells (or on edges) + tells what kind of edge it is (connected, no connection, + connection underneath the other cell). +
  • + Loose-brick view but with variable-sized content of cells: + vstreams or images. +
  • + Email flobs: emails on a coordinate system, connected + with lines indicating reply-to relationships. The flobs + may show the content, diminished as the view moves away + from the cursor. +
+ +

Problems

+ + +
+ A simple case where rendering a link in one go gives + suboptimal results. +
+ +
+ A beam with cells is even more complicated: the beam + has to be between the text and the cell background but + behind any other cells on the way to avoid cluttering + the screen. If the beams' borders should float above + the beams, then this gets even more difficult. +
+ +

+ A fairly short-term goal in the expansion of GZigZag is to make + it support 3D graphics using OpenGL, as well as retain the current + functionality using pure Java graphics. Especially useful would be + the ability to use the 2D views directly through the OpenGL layer, + as well as 3D views, and the ability to animate between the two. + +

+

+
Reusability of views +
Flexibility +
As an example, using an existing raster but putting an image + or a vstream (somehow connected to the cell) instead of + the text into the cell should be simple. +
Simplicity +
The system +
Performance +
+ +

+ If small factories are used for letting the rasters create cells, + handling depth gets more complicated. + +

+ There are also interesting problems in the rendering order of + links: if there is a link between cells that are at different + depths, then which cells should be in front. It is especially + difficult to include something like beams into this framework, + if a Z-buffer and a real third coordinate is not used. + One possibility is to split all links and beams in the middle + and render the two halves independently. However, as seen in + the beam figure, that will not be enough. + + +

Potential solutions

+ +

+ Let us start from the obvious. + +

+ For each raster, the locations and appearances (and the depths + for rendering) of the flobs must be stored somewhere quickly + accessible for the animation between rasters. + +

+ The raster must ask the flob-producer what size and aspect ratio + would be most suitable (given a shrinking factor). Being able to + cache something that was calculated (such as a line breaking) + would be most beneficial. Of course, depending on the form of + the raster, it may or may not accept the size and aspect ratio + given by the flob producer. The flobs are internally cached as + objects that know how to render themselves and how to interpolate + between two keyframes. + +

+ The links are produced after rastering, from the + coordinates of the flobs. This operation is thus well encapsulated + from changing rasters. In fact, the links do not even need to + be made into self-standing objects at all times: all that is + needed is that the FlobSet knows to call a certain method of a + certain object to plot links. + +

+ These considerations produce a rather different picture + from the current one. The classes Flob and + FlobSet would be the natural starting point. A + FlobSet, unlike the current ZZCanvas, would only store the flobs + and not the connections. The connections could be drawn just as + the flobset is being rendered from back to front. + +

+ One interesting point regarding the identification of Flobs from + the FlobSet is that the FlobSet may be hierarchical in nature. + For example when doing the VStreams-in-Cells raster, the same + vstream might be shown in two different cells (clones of each + other). Now, if flobs were identified just by their cell, then + the flobs for the spans of text would be identical and therefore + interpolated animation could do very strange things. The trivial + solution to this is to allow container flobs to exist, which + exist just to identify that certain cells are accessed through + a certain other cell. If the FlobSet has knowledge about this, + it is easy to both treat the FlobSet as flat (for e.g. beams), + or as the hierarchy (for identification of the corresponding + flob in another FlobSet for animation). + +

+ This solution is currently being tested as of 20000806. + +

Problems with the hierarchy

+ +

+ The hierarchy does not solve all the problems and + brings some new ones. + Some operations use hierarchy, some don't. +

+
Depth-ordering +
May be done with hierarchy (so the whole hierarchy branch + has a depth - effect like overlapping windows or + without hierarchy - effect like a three-dimensional cloud. + Both effects are probably useful in different situations. +
Animation +
Hierarchy is taken into account: it informs which instances + of a cell animate to which other instances. +
Link / beam display +
Hierarchy is not relevant to these except that sometimes + links/beams inside the same branch may be hidden. +
+ +

+ Because the hierarchy is kind of optional, + the hierarchy in the current prototype + is simply handled by identifying + each flob with a string ("path") and a cell. + This seems to give both enough detail and efficiency. + +

Decorations

+ +

+ Another interesting feature with the views are decorations: + things that either connect flobs between each other or + show some relationship in some other way + (for example, the three-line thing that shows the directions + of the coordinate axes). + +

+ These decorations aren't considered first-class citizens like + flobs in the current model. + This may make it possible to find extremely efficient + ways to implement them. + One obstacle to efficiency, however, is that the decorations + should be rendered at the same depth as the cells. If we have + a Z-buffer like in OpenGL, this is of course not a problem. + +

+ Now, there are several kinds of decorations: +

+
One-off +
Decorations that occur once or twice in a display, such + as the abovementioned coordinate thingy. +
Global +
Decorations that occur between most cells (at least, + most cells at a given path), such as links in the X direction. +
Overriding +
Decorations that override global decorations for selected + cells, for example if we want to show a connection that + is at the same time a clone relation by a different + visual. +
+ +

+ In order to trample over less memory, it would be nice to + be able to render global decorations for a set of cells (at + a given depth) at once. + +

+ There is one situation where decorations present a problem, + and that is when the decorations should move with the interpolation. + This is generally desirable in complicated views (e.g. email-flob) + to provide the user with additional visual cues about the structure. + There is a slightly incorrect solution that get us close to where + we want: a decoration that wants to interpolate is named a flob + and it stores references to the flobs and uses their + interpTo fields to calculate the interpolated + coordinates. The only problem is the depth: this algorithm does + not correctly alter the depth in interpolation. + However, when using java.awt.Graphics none of the other + flobs take care of their depths properly when interpolating so + it is not a problem. And if using three-D graphics, the renderer + can use the flobs' Z coordinates. + + +

Floating graphics in general.

+ +

Handles and cursors

+ +

Problem

+ +

+ One of the versions of Ted's specs specifies the following + structure for flob. + First of all, there is the central handle cell which + is the center of the flob. The flob is referred through it and + all the parts of the flob can be found through it. + That version of the spec specifies d.handle as the dimension to + reach the rest of the flob from the handle cell, and + d.ref as the dimension to use to refer to that handle cell and + thereby to the whole flob. (the spec has apparently changed + now but the changes do not affect this problem). + +

+ The cells on d.ref are basically stand-ins for the whole flob, + kind of like clones are stand-ins for a cell. + An email can be included in several mailboxes (lists of emails + running on d.2) by including cells that are on d.ref from + the original email's handle cell. + +

+ The problem, then, is basically about what is getting shown: + we'd like to be able to show +

    +
  1. The actual flob +
  2. The fact that a cursor is on the referring cell +
  3. Possibly, the contents of the referring cell +
+ This is a problem since in the current codebase, a flob + is known by one cell, whereas the above obviously + requires two cells: the referring cell and the handle cell. + Even more important is that the FlobSet knows + about the handle cell since otherwise connecting the flobs + becomes a less efficient procedure, requiring the FlobSet to + look at all referring cells to see whether they are included. + +

+ So the question really becomes: is there any point in storing + the referring cell in the flob structure, except as presentational + info about the string and cursor colors to show. + +

+ If ZZ is expanded to allow the user to place the text + insertion cursor in a cell by a mouse click, then the referring + cell is obviously needed if any of its text is rendered. + +

Current solution

+ +

+ Well, currently this is solved by having the handle cell always + be the Flob.c and if the flob has to give out + other events, it can be given a different cell. + + + + + +

Caching before saving - new file format

+ +

+ The slowest part of the current implementation, as witnessed + by time testing, is writing to the file. Also, the current file + format does not properly allow undo & branching backtracking. + +

+ The goals for the system are +

+
Write-caching +
Each cell change should not cause several system calls + to occur. Rather, cell changes should be held in memory + and flushed to disk in larger chunks every once in a while + (as the user chooses). +
Undo +
The list of operations in memory should be usable for + low-level undo operations, such as undoing writing letter + by letter. +
Granularity +
The user should be able to specify that when saved to + disk, only larger sets of changes are undoable. This may + save a lot of space, e.g. if a number of cursor moves + are compressed + to one undo set, many cells will not have changed at all. + This is especially important now that the character-by-character + editing of cell content is also done in the structure: + each insertion of a character currently saves two + cell contents: the cell being edited and the cursor cell + (giving the offset). +
Notifications +
It would be useful if the change list could also be used for + change notifications: after a set of operations is completed + (or at prespecified times) the list is examined for changes + to cells under observation. +
+ +

List format

+ +

+ It is vital that the in-memory change list is compact in format + and extremely light-weight for Java usage as it is going to be a + hot spot. + +

+ One relatively sparing implementation would be to have one long + array of Object inside which every third element would be an operation, + and the other two would be its parameters. This way, no separate + Operation object would need to be created and the references to + operations sequentially would stay memory-local: the cost + of the typecast + of Object to the Operation type is negligible compared + to the cost of accessing two or three long arrays instead of one. + +

+ There would likely be one to few Operation objects per dimension object, + which is perfectly acceptable. + +

+ The long array would have the sequence stamps and would be operable + either for undo or for committing to disk. + +

Problems

+ +

+ There is one important problem with this approach: the operations + are fairly low-level ops: this cell connected to this one, or + disconnected, or whatever. + The semantic information about an operation such as insertion + is not saved. This could be a problem with synching later on. + +

Notifications

+ +

+ In the following, N is the number of cells changed, B is the number + of observers. Also, K is the number of cells one observer typically + observes. + + +

+ It is important for the notification mechanism to be fast: specifying + a set of cells that a particular entity is interested in and scrapping + the whole set (when the entity is refreshed) will very likely be one + of the most common operations. Not trampling through a lot of memory + and being easily garbage collectible are vital considerations, as well + as good scaling w.r.t.~several things. + +

+ Observer insertion is naturally O(K) and observer removal is + either O(1) or O(K). + +

+ If a separate hashtable is used for each observer, testing which + observers to wake up is O(N*B) operation, which is not very nice. + + + +

Slices

+ +

+Slices are used for viewing a number of ZigZag spaces as one compound +space, and for sending a group of cells over to another user. +Slices are probably the most crucial aspect of the system for common use +as they will enable collaboration and upgrading. + +

+Among the issues here are +

+
Permanent IDs for versions of cells +
Specifying a group of cells for slicing. +
This is simple when the all the cells are ones edited by the user. + This gets very hairy when the user wants e.g. to send a view. Which + control cells are included? +
Reconciling differences: collaborative editing. +
A mechanism for keeping two peoples' versions of a "document" + in synch by sending minimal groups of cells across. +
d.cursor and slices. +
Having the cursors in the structure is both a blessing and a curse. + Cursors are used both for "variables" internal to the structure + with Clang and views' centers. + Their interaction with slices and versioning is unclear to say the least. +
Inclusion of a slice into multiple spaces +
What a can of worms. +
Viewing a space remotely +
Only the cells seen should be sent over. How does d.cursor + work here? +
The identity of dimensions +
If a dimension is just a string, we have a namespace problem. + Dimension being identified with a particular cell might be a solution + but this is again not without its own problems. +
Clones +
Ted wants these to be used as a solution to many problems here. + But is it possible? Can all code be made to support the situation + where suddenly one of the cells is split into two clones when + the script expected them to be together. +
Transcluding +
Taking a cell from another space with a permanent ID and connecting + its transclusion somewhere in the local space - this creates a new + version of the cell! +
d.ref and d.handle +
Interaction of higher-level items with the slice code? +
+ +

+And of course the really important question of what we're really after. +Slices have distinct, but related functionalities: +

+
Part of personal space. +
This is what Ted's example of bringing in months of the calendar + from slices is about. Each day connects to a weekday on one dimension, + and the months connect naturally in the right order by preflets. + Here, the idea is that the slice connects to the "main space". +
A fixed, distributed "package". +
For example, the default space with the default bindings for keys, or + packages that demonstrate various features. + These are less often modified by the user and are brought in by the user + and attached somewhere. + Here, the main space connects to the slice. +
Versioning. +
This is rather similar to the abovementioned fixed, distributed + packages: the user can attach the old version of some slice + somewhere, without modifying it (causing a branch) just by looking + and browsing it. + Naturally, if two versions of the same slice are brought in, the cells + should be connected along d.version or somesuch. +
+ + +

Packages

+

+ Of the above functions, the most critical one for GZigZag + currently is the packages: distributing the main default space + as a slice would be a great step: then it would be possible for + users to start stable personal spaces which would not be needed + to be brought forwards for every new version of the bindings. + +

+ The most important problems here are cursors. Just about + everything else can be resolved by explicit hook cells ("hook your + own bindings negwards on d.3 here"). Cursors are + a different matter. They are used for several things, to name + a few: + +

+
Center of view +
Selecting dimensions from dimension lists +
Selecting rasters from raster lists +
Arbitrary selections for viewing operations +
+ +

+ Additionally, there is the cursor cargo dimension which allows + cursors to piggyback on one another - for example, combining + the cursors for one view and another view's X axis allows one + to change the dimension list for the X axis by moving the other + view's center. + +

+ The default space and other packages which have views will most + likely have cursors. In order for the spaces to be useful, + these cursors should be movable when the package-slice is + included and should be movable by changing the main space, + not the package-slice. Also, cursor cargo should be changeable. + +

+ There is a simple solution to these problems: the package slices' + own d.cursor and d.cursor-cargo are + mapped to some other dimensions, e.g. d.ps-cursor. + When a slice is first incorporated into the system, the + default cursors from the slice are copied to the global + d.cursor. There then need to be operations on the + slice cell to reload or commit the cursors of a slice, which + simply copy the assignments of the cursors to the package-slice + (provided all cursors lie on cells of that package-slice as + they should) or copy the cursors from the package-slice to the + main space. + +

Most trivial slices

+ +

+ Because waiting for the full design to be finalized would + have seriously slowed down development (as the main developers + wouldn't be able to use GZZ for real work) there is + now a primitive slice implementation in place. Even in its + rudimentary form it is surprisingly complete. In addition, + this experiment gives valuable experience in the complexities + of implementing any types of slice systems. + +

+ The system works by handling two dimensions, d.slices + and (naturally) d.cursor specially. These are in + fact the only dimensions that are allowed to connect between the + slices; all others are constrained to be only among the cells + of the same slice. + +

+ The dimension d.slices simply connects the homecells + of the slices in the slice order. There are no other connections + along this dimension and it cannot be modified. + +

+ d.cursor is a different matter. In order to be + useful, even the most trivial slices must allow connections that + transcend the slices on d.cursor. In this model, + d.cursor is constrained so that the only operation + allowed is insertion negwards (currently the cursor is obtained + by going to the end of d.cursor poswards, which + will change). Also, cells in slice 0 may be inserted to any + other cell but not vice versa: cells (cursors) in other slices + may only point to cells in the same slice. + +

+ These semantics are fairly simple but still their correct + implementation is not at all trivial, especially for + d.cursor. The implementation uses preflets in + slice 0 to connect to the other slices and when reading, the + whole rank in slice 0 is placed before all the other cells in + the non-zero slice accursing the same cell, so the cursors are + not necessarily in the same order they were inserted in. + +

Adapter slices

+ +

+ One possible solution in the long term to the package-slice + problem is simply having adapter-like slices for the external + packages. These slices would have preflets pointing to s.0 as + well as the external package - possibly even without intervening + cells. + +

Versioning

+ +

+Versioning is one of the most difficult problems in defining a ZZ space. +This is because having a versioned space is not useful, unless +cursors can point to past versions of cells using the normal mechanism, +d.cursor. If views and pointing were handled outside the normal space, +this would be no problem. + +

+This immediately suggests the trivial but unsatisfactory solution of +simply not versioning d.cursor. This is unsatisfactory because d.cursor +is used for an increasing number of things, e.g. Clang variables: what +good would it be to have access to a previous state without being able +to access the values of the variables. + +

+The other solution, simply allowing retroactive changes to d.cursor +of past cells to point to the future is more attractive but not without +its own downsides. Let's say the user, at time 100 looks at a cell A at time 5 +and does some changes in the space, e.g. moves the other cursor or +writes text somewhere else, until time 105 after which he moves +the cursor away. In this case, the rank on d.cursor from cell A would +contain the user's viewcell at times 100, 101, 102, 103, 104 and 105. +This is not that great either, because the algorithm that displays the +cursor moves through d.cursor to find the coloring of the cell to show +the colors of the cursors on it. The number of cursors on past cells would +be compounded. + +

+A potentially interesting solution, avoiding the preceding problem, +is to rename d.cursor to d..cursor-past for the past cells: +a connection on d.cursor would mean that a current cursor is on the cell. +This solution is attractive, as it preserves the values of all Clang +variables "pickled" using another dimension on which they can be browsed, +but also does not grow the number of cursors on a cell too much. + + + + + +:} + + + diff --git a/Documentation/DesignProblems/linkorder.dia b/Documentation/DesignProblems/linkorder.dia new file mode 100644 index 0000000000000000000000000000000000000000..1bb0a8964a3b1b63ca932e11f6484f18f59f6954 GIT binary patch literal 677 zcmV;W0$TkaiwFP!000001MQg2lA5@{M>PLYUjLFd)NoC0z}AeNT?+0 zc-d#)@Zq2!qZ4ILS|ug1>3?_lbtmxr@|IAr#X=I!78bN!>t)${4heeF-$twBky3*A8-)Qw30_z} z3jRidZ&+v*R;69QDHmXi=)&r+^N;0}Zk!W8ANWpDibdURl5$D3iQ1r!9#t{-|KLEC_4!*N79tUXZ{U@`SyiiYEkMGB^~*i2@A_P5XZn`P zdWEN)Fm)it9S@F}X`6^P@4jDmE_C>aMHH6;189FA&!?HrSRc%!FvZC#;DR;V)t!>b z6?P<4aWkO@c5Y$V@us(m0uGpnMQ{6_MVpL{10e4vCy(L}vYE4)ZQH>ljJnY#vD74awoHNJ7|Y zmxS(nn}n0E=#%F8JgB@Im7|-f^g7*8!fZcTY%1ZG>?+Okc~EIUNegFn7h67IDTXY-`* zf#yWkoK^pTSd*1KXlsxZ&-)vw{ynLY_G@8zt$TXys2*k`pgQ}-dHzyh**ke_u. He has written most of the code in GZigZag (and +most of it while traveling on trains). + +This maintainership is by proxy from Ted Nelson, who has the official +maintainership but who does not program. + +----- +5. How complete/stable is GZigZag? + +It's pre-alpha. It is already usable for many things but it is nowhere +near feature complete yet. + +As for stability, crashes are quite rare but the development speed is high. + +----- +6. What are some planned features? + +See Java/TODO in the distribution. + +----- +7. Are there any mailing lists associated with ZigZag/GZigZag? + +See http://www.xanadu.com/zigzag + +----- +8. How can I help? + +Email Tuomas Lukka and ask. + + +============================================================= +Section II: Using (G)ZigZag + +1. How can I learn to create my own structures so that they work well? + +There are some ideas in the document "A Gentle Introduction to ZigZag", +available under the + + Documentation/Gentle_Introduction + +directory on the CVS, or as a postscript file from the web page. + +============================================================= +Section III: Questions specific to the Java version + +1. Why Java? + +Portability, garbage collection, SPEED (with JIT: for linux, IBM's +JDK-1.1.8 is GREAT), portable graphics, easy C interface, available APIs +(e.g. JMF), etc. + +You will note that I did not mention the language itself above: +I don't like the language itself that much: I'd prefer to work in +Perl. Unfortunately it does not provide all of these other features and +the ones it does it does not provide as easily and conveniently as Java. + +----- +1.1 Where do I get Java sources for GZigZag? + +If you know CVS, you can checkout module GZigZag in +:pserver:anonymous@cvs.gzigzag.sourceforge.net:/cvsroot/gzigzag . +Otherwise, you can use our nightly-generated source snapshots +available at ftp://gzigzag.sourceforge.net/pub/gzigzag/snapshots/ . +They are packaged in GNU-Zipped tar archives and in ZIP archives, +choose whichever is best for you. + +The Java sources are located in the Java/ subdirectory of the full +source tree. + +----- +1.2 Where do I get precompiled class files for GZigZag? + +We have a build daemon that builds the current CVS version nighly and +puts two JAR archives of it in +ftp://gzigzag.sourceforge.net/pub/gzigzag/snapshots/ . The +-without-modules version contains the core GZigZag. The -with-modules +version is much larger and contains some additional functionality. + +----- +1.5. It's WAY too slow! Are you out of your mind? + +No. For me, it's quite comfortable on my 233MHz Pentium 80Mb laptop. +There are several possible reasons for this: + +* You are using a Java interpreter without a JIT (Just-In-Time) + compiler. As mentioned in the answer to the previous question, for + Linux, I recommend IBM's JDK 1.1.8. Do NOT ask me about proprietary + operating systems - GZigZag works there but over there you're on + your own for platform-specific questions. Another quite fast JVM is + Kaffe, but unfortunately at least some versions of Kaffe have a + nasty bug that makes using GigZag on it quite unpleasant. + +* Your Java interpreter is not using enough memory. By default, some Java + interpreters only use 16Megs at maximum. Try starting with + + java -mx30m -ms30m foo.Main + + to set it to allocate 30Megs at startup (or more if you have enough memory). + That way it won't be garbage collecting constantly and you may get quite a + significant performance improvement. + +----- +1.5.1. I can't use IBM's JDK: it doesn't have the Swing classes + +You are using an old version of GZigZag. Current CVS versions and +snapshots do not require Swing. + +----- +1.9. I want to report a bug; how do I do that? + +There are instructions about this in http://www.gzigzag.org/bugs.html . + +----- +2. How is the Java code structured? + +ZZCell and ZZSpace are the center of it all. Start from there and +also ZZDimension, ZZDimSpace, ZZLocalDimension, ZZPersistentDimension, +ZZPersistentDimSpace ... +These latter ones are still a bit new and finding their places. + +----- +3. Why is the ZZEventQueue not called / what is ZZObs / ... ? + +Legacy. It's currently supplanted by the ZZUpdateManager for view updates +but may be revived later. + +----- +4. What is the saved file format? + +See the Java/storage/ and Java/media subdirectories of the source +tree, especially storage/Recs.java, storage/ZZPersistentDimSpace.java +and media/StringScroll.java. + +----- +5. Will my files be upwards compatible? + +No: the format will change soon. However, you can dump the space into XML +(will be explained later) and restore it to the new file type. + +----- +6. Are there any coding standards? + +See the file CODING in CVS. + +----- +7. Do you accept patches? + +Yes, we do, but it helps if you consult with us first to make sure your +intended change is in a reasonable direction. Much functionality should go +into the Modules/ as well. + +diff -u (unified diff) is preferred. + + +----- +8. What are the advantages of the new Java version over the old Perl version? + +- Graphics. You just need to see the vanishing view to see why it's important. +And that's just the beginning. + +- Active development. + +----- +9. What are the disadvantages of the new Java version over the old Perl version? + +- Ted's own keystrokes do not yet work (to be fixed soon) + + + +============================================================= +Section III: Questions specific to the Perl version + +1. Wasn't there a Perl version or something? + +Yes, written by Andrew Pam and others. + +----- +2. Are the files from the Perl version compatible with the new Java version? + +No. + +----- +3. Is it possible to import files from the Perl version to the new Java version? + +Not yet, but soon. Only needs a short Perl script to read the DB_File from +the Perl version and write the corresponding XML code and then you can import +it. diff --git a/Documentation/Gentle_Introduction/Makefile b/Documentation/Gentle_Introduction/Makefile new file mode 100644 index 0000000..4f2f387 --- /dev/null +++ b/Documentation/Gentle_Introduction/Makefile @@ -0,0 +1,19 @@ +all: gi.html gi-ns4.html +# zzgentle.tex +zzgentle.dvi: zzgentle.tex + pic -t <$*.tex >$*.tex + latex $* + cat $*.dvi >$*.dvi +ps: zzgentle.ps + +# DIAGRAMS=linkorder.png beamorder.png +DIAGRAMS=../wmlinc/article.wml + +gi.html: gi.wml $(DIAGRAMS) + +gi-ns4.html: gi.wml $(DIAGRAMS) + +include ../lib.mk + + + diff --git a/Documentation/Gentle_Introduction/README b/Documentation/Gentle_Introduction/README new file mode 100644 index 0000000..f9034f8 --- /dev/null +++ b/Documentation/Gentle_Introduction/README @@ -0,0 +1 @@ +Requires latex and the xypic package for latex. diff --git a/Documentation/Gentle_Introduction/gi.wml b/Documentation/Gentle_Introduction/gi.wml new file mode 100644 index 0000000..0975fb7 --- /dev/null +++ b/Documentation/Gentle_Introduction/gi.wml @@ -0,0 +1,586 @@ + + + + + + A Gentle Introduction to Ted Nelson's ZigZag Structure +#include '../wmlinc/article.wml' + + +{: [[s/(?)\b(d\.+\w+)/\1<\/code>/g]] +

A Gentle Introduction to Ted Nelson's ZigZag Structure

+
$Id: gi.wml,v 1.4 2000/10/21 13:45:30 tjl Exp $
+ + Tuomas Lukka
+ lukka@iki.fi
+
+
+ + + +

+This document provides a short introduction to the abstract ZigZag +structure and gives some pointers for designing structures for various +applitudes. Unlike most of the other documentation related to GZigZag, +this document is more about the abstract structure, not this one particular +implementation. + +

+This introduction, even though it is short, is still +rather technical and detailed +and therefore the even gentler manuscript "GZigZag: a platform for +Cybertext Experiments" is recommended to be read before this document. + +

+This is work-in-progress: if there are any unclear parts, feel +free to ask me to clarify things. + + + +

Introduction

+ +

+The best words I've heard to describe the ZigZag structure +are "hyperstructure kit". It is a set of tools or primitives for +building hyperstructures. +ZigZag was invented by Ted Nelson and is currently being implemented +as a prototype at the University of Jyväskylä under the direction of +the author. +The purpose of this document is to introduce +the reader to the ZigZag structure and some example applications of +it. + +

+This document was written using material and ideas from +documents by and discussions with Ted Nelson, +but also contains original ideas and material. + +

+See also the glossary of ZigZag terminology in XXX. + +

Basics

+ +

+To arrive at ZigZag from a general perspective, consider the problem +of storing and visualizing information in a structure. +Now, we naturally need some kind of ``atoms'', i.e.~indivisible +pieces of information --- let's make an atom connected to a piece of text +as the information it carries. Now, atoms should be connected to each other. +Consider the two principles: 1) all connections must be two-directional +and 2) to preserve visualizability, no cell should have an enormous number +of connections. There are of course several different ways of realizing +these principles but ZigZag is a particularly simple one. + +

+ZigZag is a paradigm for manipulating data and devices, a platform +if you may, in some way like UNIX. In UNIX (at least originally), everything +is a file. Whether it is really a printer or the console or a network +connection doesn't matter: the same basic operations (or at least +a subset of +them) is available. ZigZag is quite similar: everything is a cell and +connections between the cells. However, the structure set up by ZigZag is +far richer than a hierarchical file system, allowing more interconnectivity +between related information. + +

+All data in ZigZag consists of cells. +A cell can contain e.g. text, an image +or something like that --- basically, a unit of data. +It does not matter how the content is stored; simply +think of a cell as a little +bit of data that has no significant internal structure (except of course the +sequence for text, the places of the pixels for an image etc). + +FIGURE + +

+
+ +

+The cells are the primitives of the structure and the structure is formed +by connecting cells to each other through dimensions. +In each dimension, each cell can have one positive and one negative +neighbour. This means that all connections between cells are +two-directional: we speak of being neighbour to, or connected to, +not of linking to since linking nowadays means one-directional HTML-like +links. +The different dimensions are denoted by names, such as d.1 or d.clone. + +

+Now, if we have two dimensions and the cells are connected in a regular +lattice, then this corresponds to a normal spreadsheet. However, no +restriction is placed on which positive and negative ends are connected +together - this is why this is called the ZigZag structure. All kinds +of structures are possible: loops, M\oe bius strips, spheres etc. +The kind of structure to choose for your application is up to your +imagination. + +

+However, locally, from the perspective of one or two cells, this will +still look like the spreadsheet: each cell has its neighbours and +you go from it to one direction and then turn around and come back in +the opposite direction, you end up in the same cell. So locally this +structure is logical and simple --- like a spreadsheet --- but globally +it is paradoxical: you can just keep going into one direction and +arrive back where +you came from, for example, or you can go left, down, right and up, +and +{\em not} come back where you started from in the end. +This property gives more room in ZigZag for putting things +in than a spreadsheet has, for instance. + +

+One good way of visualizing this kind of structure is to think a +device commonly found in science fiction books and films: a hallway +with several doors. One door leads to a desert, and another to the +antarctic. When you go through the door, you are in a different place +but you can still walk back through the door, open the other door and +walk through it. At each moment separately, you are operating under +the rules of three-dimensional space known to us but when you pass the +door and realize that you don't see the other door from the other side, +you know that you are in a paradoxical environment. + +

+Another place to look for good, related visualizations, is the work +of M.C.Escher, who has created many paradoxical spaces that would fit +well with ZigZag. However, not all of his paintings work this way: in ZigZag, +directions are global: up is the same ``up'' everywhere, unlike in some +of Escher's work, so care has to be taken with this analogy. + +

+A slightly different way of looking at the structure that may sometimes +help thinking about it is to consider dimensions +as {\em labeled lists} of cells. +That is, instead of considering cells and connections, consider lists (each +list labeled with a string) of +cells where the same cell may be on several lists (but only one +with any given label). +It is not difficult to see that this is exactly the same +structure as above but viewed from a different angle: emphasizing the ranks +instead of the single cell and its connections. + +

+As an example of such a structure, consider a list of people and their +birth years. It'd be quite natural to have first names, last names and +birth years in their own columns, each row being one person. +If done e.g.~on a spreadsheet, you would have to settle +for the global rectangular structure. However, with ZigZag you can +do more interesting things such as have the first names in alphabetical +order, the last names in alphabetical order and finally even the birth +years in numerical order in their own colums. This is because the columns +are independent of each other, bound together simply by having the rows +going across them. Displaying such a structure can be done in several +different ways. +Also, it would then be easy to select subsets of the people on other dimensions, +for example for people who are currently in the same class or whatever. + +

+It is useful to be able to see the structure from both perspectives +since this will both help to overcome the feeling of paradoxicality +from the spreadsheet-like connective picture but also remember that +the cells are important objects in the list picture. + +

Comparing ZigZag with existing computer structures.

+ +

+To put it coarsely, outside ZigZag there are three different kinds of +structures in computers today: linear lists (and grids i.e.~lists of lists), +hierarchical trees and messes. That is really messes, not meshes. By +a mess, I mean any complicated data structure, usually with one-directional +links to make things even more unmanageable. + +

+The first two are inflexible, even with one-directional +hierarchy-crossing links +such as symlinks in filesystems or XML IDs. +The third always requires much +programming and debugging to do and is often hard to visualize. + +

+ZigZag offers a fundamental new kind of structure where encoding +new structures is simple because the coherence of the underlying +simple flexible structure is guaranteed. +At first it may seem strange that a structure that restricts the +number of connections from each cell can be generic but this simple +restriction is what brings about the coherence of ZigZag. +In the sections below you'll see how this restriction does not prevent +any structure from being represented using ZigZag but it enables several +clever visualizations. + +

+Among other things, +ZigZag guarantees that there are no dangling pointers: all links are +two-directional. You can always find which cells refer to a given cell. + +

+One interesting thing to note +about ZigZag and existing structures, +the importance of which I really only realized while doing a demo at Nokia +is simply that by using different dimensions, ZigZag allows you to +arrange the same things into different traditional +structures. So you can have the same cells in a tree along two +dimensions (as you'll see below, trees are easiest done using two +dimensions, one to go from the parent to the first child and the other +to move along siblings), a list along another dimension and a table +along two other dimensions. And possibly another tree in yet two more +dimensions, if desired. +If you use relcells (see below) +you can even put the same things (this time, not cells: you do have to do a step of indirection) +into different structures along the +same dimensions. + +

Viewing

+ +

+Now that the structure is defined, we have to be able to view and edit +it on the computer somehow. Of course, we could just put this +structure in a text file and edit it by naming cells with numbers and +links by naming the cell numbers but this would lose the visuality +inherent in the design. + +

+There are many variations to the theme of viewing +ZigZag structures. Views range from generic to specific views. +Generic views are designed to be useful with a wide range of structures +and usually therefore show only a small number of dimensions +or a small number of steps along each dimension. +Specific views on the other hand are free to do anything that +suits the application at hand. + +

+Specific views are related to applitudes, explained below +in more detail. + +

+In this section, we look at the structure of several generic views. +Before going to the views themselves, let us first define some terms: +the raster and the view. +A raster is a way of selecting cells from the structure. +A view is a way of placing the selected cells on the screen. + +

+In order to look clear to the human observer, visual cues about the +structure are vital. All neighbouring cells that lie next to each other +should be connected with a line, and all cells that have neighbours +that were not displayed because of the raster should have e.g. half of a +connecting line, disappearing underneath the other cell in some visual +fashion to show this. Also, when moving in the structure so that the +part of + + +

2D rectangular views

+ +

+ The 2D rectangular views are characterized by placing the + cells in a spreadsheet-like rectangular grid on the screen. + Even here, there are many different possible + rasters for choosing which cells to place where, since + a general ZigZag structure will not fit a rectangular grid + and parts have to be clipped out. + Note that the 2D here refers to the two-dimensionality of the + rectangular grid, not that there need to be only two dimensions + of the ZigZag structure showing. Usually we only have two + in these views but as we see below, this is not a requirement. + +

+ The two simplest rasters useful for the rectangular views + are the row and column rasters, which are actually + the same raster but placed on the screen rotated 90 degrees + from each other. + These rasters are genuinely two-dimensional: they only + use two dimensions in the ZigZag structure to find cells + to display. + +

+ The row/column raster + starts from the cursor and moves along one ZigZag dimension + and place cells on the center column/row of the grid. + After that column/row is full, the raster starts from + the cells placed and from each, moves along the other + dimension and places the cells found along the other + dimension there. + +

+ These rasters are called hard rasters: + the arrangement of cells is fixed so that there is + only one possible path from the cursor to a cell to be + placed in a given position on the screen. If there is no + cell in the structure along such a path, then that + location is left empty. + +

+ The converse of hard rasters are the soft rasters + where there can be several different paths for + each cell of the on-screen grid. + The point of soft rasters is that since ZigZag structures are + often relatively sparse in terms of connections, the + hard row and column rasters may show relatively few cells at + a time. Soft rasters are able to show more of the structure + at the same time. + +

+ There are many different ways to define soft rasters for + the rectangular grid. One fairly useful way is to specify + the soft raster so that all the cells that a certain hard + raster would show are shown, but additionally, if there + is space left, more cells are shown along the dimensions. + + +

Vanishing view

+ +

+ The vanishing view looks a little like the hard row/column + raster above but is in fact a completely different beast. + The raster for a vanishing view consists of all the cells + within a given 2- or 3-dimensional Manhattan distance + from the cursor (a Manhattan distance simply means the number + of connections in any direction to get from one cell to another). + +

+ These cells are then placed on screen starting with the center + cell and reducing the cell size as the distance from the cursor + grows. This causes cells that would be in the same slot + in the rectangular grid to be plotted apart from each other. + +

+ This could easily be generalized to more than three dimensions. + +

Compass view

+ +

+ The previous views have dealt with a few dimensions but several + steps along those dimensions. The compass + +

Multicentric views

+ +

+ XXX + +

Text view

+ +

+ One simple view that can be easily overlooked is to simply + take a rank of cells and show their texts appended to each other. + +

Applitudes

+ +

+To distinguish itself from the traditional, monolithic applications, +ZigZag uses the term applitude for a "zone of functionality". +The difference between applications and applitudes is the interconnectivity: +whereas conventional, monolithic applications are used to having all data +in their own files, applitudes can easily share cells and simply use +their own, orthogonal dimensions to connect cells. + +

+The differences caused by this simple shift are enormous: instead +of a selection of monolithic blocks, the contents of the computer can +become an interconnected, organic whole. +Everything connected to a particular person, for example, is +connected to the same cell, whether in the email applitude, the calendar, +the collection of documents or anything. + + +

Designing structures

+ +

+In this section, we'll go through some commonly occurring +structural patterns in ZigZag. These can be thought of as being +analogous to Design Patterns in Object-Oriented Programming. +The patterns here are not formalized as far as OO design patterns +but carrying out such a treatment would not be difficult. + +

+As you will see, there are several different ways of encoding +the same conceptual structure in ZigZag. The choice between +using a different dimension or a rank of clones, for example. +These alternative codings resemble in some way one of XML's +similar ambiguities: for example whether to code something as an attribute +or as a contained text-only element. + +

+It is important to understand the difference +between the low-level structure and the implied, higher-level +structure. Single cells and single connections are building +blocks, not necessarily complete entities by themselves. +

Cloning

+ +

+ One of the basic structural mechanisms in ZigZag is + cloning, i.e. connecting cells on d.clone to imply that + they are somehow the same as the root clone, i.e. negend + of d.clone. + +

+ This mechanism is coupled with the cell content: + the contents of all clones is the same as the contents + of the root clone, and editing a clone edits the root clone. + +

+ XXX + +

+ There are alternatives to cloning, and in many cases they + may be preferable. + For instance, in a calendar applitude it would be possible + to clone the cells for persons into the structures + representing meetings but a possibly preferable approach + would be to use an applitude-specific dimension for this. + The reason is that then this dimension would always lead + to predictable structure and the applitude could + easily give interesting visualizations of the meetings + a person participated or will participate in. + +

+ This is a fairly unsettled question. With more experience + in designing different applitudes we will be able to tell easier when + clones are appropriate and when special dimensions are better. + +

Arrangement along a dimension

+ +

+ Sometimes, there is a good, unique way of arranging cells along a + dimension, e.g. alphabetical order. However, sometimes there is not, + or there are two different orders you'd like to have. + +

+ This may seem like a difficult problem but actually, if all + but one of the desired orders are easy to determine from the + neighbours of the cells, then there is no problem at all: instead + of expressing it directly in the structure, those orderings that + are easy to construct algorithmically should be delegated to + the view (as of yet, there are no viewers capable of this but + they are under construction). + +

+ Another alternative (that does not currently work) will be + to thread the cells through several dimensions, most of which + are implicit: for example, an implicit d.1-alphabetic could + have the same ranks as d.1 but alphabetized. The implicit + dimensions would be read-only and be updated automatically + when the corresponding real dimensions changed. + +

+ If there is more than one order that is not easily determinable, + then using two dimensions or cloning becomes a thing to + consider. + +

Many to one reference

+ +

+ Even though the structure only allows only + two connections along each dimension, it + is possible for + many cells to refer to one in ZigZag. + This works by the way outlined above, by building + a higher-level + structure from the low-level building blocks of the cells + and connections. + +

+ There are of course + different ways for creating many to one reference, + but two main ones distinguish themselves. + +

+ If the cell referred is very different from the + cells referring to it, then a single rank, where + the referred-to cell is the headcell is a good choice. + Clones, for example, work this way (see above). + +

+ If the referents can be of the same "type", then + it becomes necessary to allow the cell referred to to + refer to another cell. In such case, a construction called + a corner list is used. + A corner list works by using two dimensions: + the first one connects all the cells referring to a given + cell and the second one connects the referred-to cell + to the headcell of that rank. + There are two main variants: the empty-headed + one where the headcell is + empty and the solid one where the headcell is one of the referring + cells. The insert and delete referring cells operations are + simpler for the empty-headed list since all referring + cells are in the same position but that configuration wastes + one cell. + + +

Hierarchies

+ +

+ A hierarchy can be understood as a many-to-one reference + relation, with the children of a given cell being the + cells referring to it. + +

+ This would make a tree mapped as in the figure XXX. + +

+ It is good to remember that the same cells can be in + several different trees using different dimensions. + +

Relation cells

+ +

+ Relation cells (relcells) are a commonly occurring construct + in ZigZag. Fundamentally, relcells exist to declare a relationship + between two cells or two groups of cells. + +

+ One example of a relcell would be the empty headcell in the + empty-headed version of the corner list above. + However, this is a fairly untypical example. + +

+ Typically, a relcell is on two or more ranks and implies + a relationship between the headcells of those ranks. + This way, each cell can have the same relationship to + several other cells at the same time. + +

+ A good example of the use of a relation cell is + the genealogy applitude (pardon the obvious puns). + The idea is to connect all the siblings on one rank in the family + tree and married couples on another, but this leaves + open the question of representing the children born in the marriage. + This is solved by placing a relcell between the parents, + and hanging the sibling rank off that cell as the headcell. + This relcell then implies a parent-child relationship between + the cells connected to it.. + +

Example applitudes

+ +XXX + +

The Cousin Problem

+ +

+ There is one important problem when dealing with data + that has relations, which the author calls the "Cousin" problem. + Consider the genealogy applitude. + Now, insert a new person, A, and then his cousin, B. + A moment's reflection will show that this is impossible + in the data structure explained above. + +

+ This is because in the human representation of concepts, + there is no hierarchy between mother, father, son, daughter and + cousin. There is no good way to pick just one way to represent + the information since the idea "B is A's cousin" is perfectly + valid, even without knowing whether it is on the mother's or + father's side. + +:} + + + diff --git a/Documentation/Gentle_Introduction/zzgentle.tex b/Documentation/Gentle_Introduction/zzgentle.tex new file mode 100644 index 0000000..c867c85 --- /dev/null +++ b/Documentation/Gentle_Introduction/zzgentle.tex @@ -0,0 +1,1280 @@ +% Copyright(C) 1999 Tuomas J. Lukka +% Redistribution permitted +% +% XXX redo pics in gpic. +% +% +\documentclass[12pt]{article} + + +\usepackage{rcs} +\RCS $Date: 2000/09/13 14:55:57 $ +\RCS $Revision: 1.17 $ +\date{Rev.\RCSRevision~~\RCSDate} + + +\usepackage{umlaut} +\usepackage{times} +\usepackage{xy} +\xyoption{frame} +\xyoption{matrix} +\xyoption{arrow} +\xyoption{curve} +\renewcommand{\Large}{\LARGE} + +\CompileMatrices + +\title{\bf \Huge A Gentle Introduction to +Ted~Nelson's ZigZag\footnote{ZigZag is a trademark of Ted Nelson}~ +structure} +\author{Tuomas J.~Lukka, {\tt lukka@iki.fi}} +\begin{document} +\maketitle +% \begin{abstract} +% \end{abstract} + +\tableofcontents +\listoffigures + +\section{Introduction} + +\def\zz{ZigZag} +ZigZag is a generic data structure, not tied to any particular application +but quite generic in nature. The purpose of this document is to introduce +the reader to the ZigZag structure and some example applications of +it. This document was written using material and ideas from +documents by and discussions with Ted Nelson, +but also contains some ideas the author believes to be original. + +\zz\ was invented by Ted Nelson and is currently being implemented +as a prototype at the University of Jyväskylä under the direction of +the author. + +Note that while the basic structure of \zz, i.e. cells, ranks, dimensions +is fixed, the more particular aspects, i.e. particular dimensions by name, +the actions (executable code in the structure), the interaction between +different \zz\ spaces, distributed \zz\ etc.~are still very much being +developed. We have a prototype and are experimenting with it but +we need more experience with actual applications in order to understand +the system better. +If you feel you can help and want to get in on the action, contact +the author or Ted Nelson himself. + +\section{Basics} + +\zz\ sets up a paradigm for manipulating data and devices, a platform +if you may, quite like UNIX. In UNIX (at least originally), everything +is a file. Whether it is really a printer or the console or a network +connection doesn't matter: the same basic operations (or a subset of +them) is available. \zz\ is quite similar: everything is a cell and +connections between the cells. However, the structure set up by \zz\ is +far richer than a hierarchical file system. + + +\subsection{The \zz\ structure} + +All data in \zz\ consists of cells. A cell can contain e.g.~text, an image +or something like that --- basically, an indivisible atomic unit of data. +It may be implemented in terms of a reference to a larger unit of data +but for now, this is not significant. Just think of a cell as a little +bit of data that has no significant internal structure (except of course the +sequence for text, the places of the pixels for an image etc). + +\begin{figure} +\caption{a) A cell with some data inside (the string ``Cell A''). +b) Two neighbouring cells: Cell B is poswards on the dimension {\tt d.1} +from Cell A (and conversely, Cell A is negwards +on the dimension {\tt d.1} from Cell B. +c) Two intersecting ranks, one in {\tt d.1} and the other in {\tt d.2}. +The cells in the two ranks are BCDE and ADFG. +The negend of the one on {\tt d.1} is B and the posend of the same rank +is E. The negend and the posend of the other rank are A and G, respectively. +% +%Note that there are six other ranks +%in this picture as well, each of length one: +%namely, A, F, G in {\tt d.1} and B, C, E in {\tt d.2}. +%Usually these ranks of length one will not be mentioned or talked +%about as ranks +%but they are still ranks in the sense that every cell is on every dimension. +\label{fig:onecell}} +a) +%\xymatrix{ +%*+[F]\hbox{Cell A} +%}~~~~~ +.PS +boxwid=0.6 +boxht=0.25 +box "Cell A" wid 0.6 ht 0.25 +.PE +\box\graph~~~~ +b) +%\xymatrix{ +%*+[F]\hbox{Cell A} +%\ar[r]^{\tt d.1} & +%*+[F]\hbox{Cell A} +%} +.PS +box "Cell A" same +arrow "\tt d.1" "" +box "Cell B" same +.PE +\box\graph~~~~~ +% \xymatrix { +% && *+[F]\hbox{A} \ar[d]^{\tt d.2}& \\ +% *+[F]\hbox{B} \ar[r]^{\tt d.1} & +% *+[F]\hbox{C} \ar[r]^{\tt d.1} & +% *+[F]\hbox{D} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2} & +% *+[F]\hbox{E} +% \\ +% && *+[F]\hbox{F} \ar[d]^{\tt d.2}& \\ +% && *+[F]\hbox{G} & \\ +% } +.PS +move down ; +right; +B: box "B" wid 0.3 ht 0.25; +arrow "\tt d.1" ""; +C: box "C" same ; +arrow "\tt d.1" ""; +D: box "D" same ; +arrow "\tt d.1" ""; +E: box "E" same ; +move to D.s; +down; +arrow "\tt d.2" ""; +box "F" same; +arrow "\tt d.2" ""; +box "G" same; +A: box "A" same at D .n + (0,0.75) +arrow "\tt d.2" "" from A .s to D .n; +.PE +c)\box\graph +\end{figure} + +\begin{figure} +\caption{a) A paradoxical, non-spreadsheet-like structure. +There are two ranks that are longer than one: BCDE on {\tt d.1} and ADFBG on {\tt d.2} +b) A different view of the same paradoxical structure. +\label{fig:paradox}} +a) +% \xymatrix{ +% && *+[F]\hbox{A} \ar[d]^{\tt d.2}& \\ +% *+[F]\hbox{B} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2} & +% *+[F]\hbox{C} \ar[r]^{\tt d.1} & +% *+[F]\hbox{D} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2} & +% *+[F]\hbox{E} \\ +% *+[F]\hbox{G} && *+[F]\hbox{F} +% \POS"2,1"**\crv{[]-(0,20)&"3,1"-(0,20)&"3,1"-(20,0)&"2,1"+(0,20)}?>*\dir{>}?(.05)*!R!/^5pt/{\tt d.2} +% & \\ +% } +.PS +move down ; +right; +B: box "B" wid 0.3 ht 0.25; +arrow "\tt d.1" ""; +C: box "C" same ; +arrow "\tt d.1" ""; +D: box "D" same ; +arrow "\tt d.1" ""; +E: box "E" same ; +move to D.s; +down; +arrow "\tt d.2" rjust ""; +F: box "F" same; +move to B .s; +arrow "\tt d.2" ""; +box "G" same; +A: box "A" same at D .n + (0,0.75) +arrow "\tt d.2" "" from A .s to D .n; +move to F.s ; +spline down then left 2.1 then up 2 then right 0.5 to B.n ->; +.PE +\box\graph~~~~~ +.PS +boxwid=0.3;boxht=0.25; +down; +box "A"; arrow "\tt d.2"; D: box "D"; arrow "\tt d.2"; +box "F"; arrow "\tt d.2"; B: box "B"; arrow "\tt d.2"; +box "G"; +right; move to D.e; arrow "\tt d.1" ""; box "E"; +move to B.e; arrow "\tt d.1" ""; box "C"; +spline right then down 1 then down 0.5 left 2.0 then up 2.5 to D.w ->; +.PE +b)\box\graph +% \xymatrix{ +% *+[F]\hbox{A} \ar[d]^{\tt d.2} & \\ +% *+[F]\hbox{D} \ar[d]^{\tt d.2} \ar[r]^{\tt d.1} & *+[F]\hbox{E} \\ +% *+[F]\hbox{F} \ar[d]^{\tt d.2} & \\ +% *+[F]\hbox{B} \ar[d]^{\tt d.2} \ar[r]^{\tt d.1} & *+[F]\hbox{C} +% \POS"2,1"**\crv{[]+(30,0)&"5,1"+(20,-10)&"5,1"+(10,-10)&"5,1"+(-5,-10)&"2,1"-(30,0)}?>*\dir{>}?(0.05)*!R!/^5pt/{\tt d.1}\\ +% *+[F]\hbox{G} & \\ +% } +\end{figure} + +The \zz\ structure is organized according to {\em dimensions}. These +are just directions --- normal spreadsheets have two, x and y, and \zz\ +has an unlimited number. Dimensions are told apart from each other by +name --- like {\tt d.1} or {\tt d.clone}. + +In each dimension, each cell has a positive end and a negative end. Each +positive end can be connected to exactly one negative end (and vice +versa) in the same dimension. In diagrams, this connection is often +shown as an arrow or a line, possibly labeled with a dimension if it is +not evident from the context. A cell connected to another cell in the +positive direction on dimension {\tt d} is called the cell's posward +neighbour on {\tt d}. + +Now, if we have two dimensions and the cells are connected in a regular +lattice, then this corresponds to a normal spreadsheet. However, no +restriction is placed on which positive and negative ends are connected +together - this is why this is called the \zz\ {\em structure}. All kinds +of structures are possible: loops, M\oe bius strips, spheres etc. +The kind of structure to choose for your application is up to your +imagination. + +However, locally, from the perspective of one or two cells, this will +still look like the spreadsheet: each cell has its neighbours and +you go from it to one direction and then turn around and come back in +the opposite direction, you end up in the same cell. So locally this +structure is logical and simple --- like a spreadsheet --- but globally +it is paradoxical: you can just keep going into one direction and +arrive back where +you came from, for example, or you can go left, down, right and up and +{\em not} come back where you started from. + +One good way of visualizing this kind of structure is to think a +device commonly found in science fiction books and films: a hallway +with several doors. One door leads to a desert, and another to the +antarctic. When you go through the door, you are in a different place +but you can still walk back through the door, open the other door and +walk through it. At each moment separately, you are operating under +the rules of three-dimensional space known to us but when you pass the +door and realize that you don't see the other door from the other side, +you know that you are in a paradoxical environment. + +Another place to look for good, related visualizations, is the work +of M.C.Escher, who has created many paradoxical spaces that would fit +well with \zz. However, not all of his paintings work this way: in \zz, +directions are global: up is the same ``up'' everywhere, unlike in some +of Escher's work, so care has to be taken with this analogy. + +Another possible way of viewing this structure is the electric circuit view +where the cells are just drawn as blocks with {\tt +} and {\tt -} +connectors labeled with dimensions. Wires (connections) can now be drawn from +any {\tt +} to any {\tt -} connector in the same dimension. + + +Finally, let's go through the vocabulary of \zz: +\begin{description} +\item[cell] The basic unit of information +\item[dimensions] Orthogonal directions along which ranks of cells run. +\item[neighbour] The cell next to another cell on a given dimension. Either poswards or negwards +\item[rank] A number of cells that are neighbours to each others, that is, a list that a +given dimension runs through. Note that all cells are on ranks in all dimensions; many of them +are simply on ranks of length one by themselves. +\item[negwards, poswards] The two directions on each rank/dimension. +\item[negend, posend] The most negwards/poswards cell of a rank. +\end{description} + +The words {\em row} and {\em column} are not on the list, and there +is a reason for this: a row is just a rank viewed horizontally and +a column is a rank viewed vertically. The same rank can be seen, depending +on the view, as either a row or column. + +\subsection{A different perspective} + +A slightly different way of looking at the structure that may sometimes +help thinking about it is to consider {\em labeled lists}. +That is, instead of considering cells and connections, consider lists (each +list labeled with a string) of +cells where the same cell may be on several lists (but only on ones +with different labels). +It is not difficult to see that this is exactly the same +structure as above but viewed from a different angle: emphasizing the ranks +instead of the single cell and its connections. + +As an example of such a structure, consider a list of people and their +birth years. It'd be quite natural to have first names, last names and +birth years in their own columns, each row being one person. +If done e.g.~on a spreadsheet, you would have to settle +for the global rectangular structure. However, with ZigZag you can +do more interesting things such as have the first names in alphabetical +order, the last names in alphabetical order and finally even the birth +years in numerical order in their own colums. This is because the columns +are independent of each other, bound together simply by having the rows +going across them. Displaying such a structure can be done in several +different ways. + +Also, it would then be easy to select subsets of the people on other dimensions, +for example for people who are currently in the same class or whatever. + + + +\begin{figure} +\caption{ +} +XXX!!! +\end{figure} + +It is useful to be able to see the structure from both perspectives +since this will both help to overcome the feeling of paradoxicality +from the spreadsheet-like connective picture but also remember that +the cells are important objects in the list picture. + +\subsection{Arriving at the ZigZag structure} + +To arrive at ZigZag from a general perspective, consider the problem +of storing and visualizing information in a structure. +Now, we naturally need some kind of ``atoms'', i.e.~indivisible +pieces of information --- let's make an atom connected to a piece of text +as the information it carries. Now, atoms should be connected to each other. +Consider the two principles: 1) all connections must be two-directional +and 2) to preserve visualizability, no cell should have an enormous number +of connections. There are of course several different ways of realizing +these principles but ZigZag is a particularly simple one. + +\subsection{Special system dimensions} + +At the time of the writing, some of these dimension are still in GZigZag +with their old names and semantics, most notably d.stepper (which goes +by the handle d.cursor). + +Usually dimensions that are closely related to each other have +related names, like {\tt d.stepper} and {\tt d..stepper-cargo} below. + +Some dimensions have special meaning to \zz. Among them are +\begin{description} +\item[d.clone] The clone dimension. All cells on a clone rank are clones of each other, meaning +that their contents are enforced to be the same and changes to the contents of one are reflected +to the others. + +For example, clones could be used to represent the same email address +on a number of email headers, so that all those instances of the +same email addresses would be linked to each other through {\tt d.clone}. +\item[d.stepper] A pointing dimension. The negend of a rank on +{\tt d.stepper} is the cell being pointed at by all of the other cells +on that rank. + +This mechanism is used for instance by the views to point to the cursor which is +at the center of the view. Moving the cursor is equivalent to inserting +the maincell of the view poswards on {\tt d.stepper} from the new position +of the cursor (the accursed cell). + +\item[d..stepper-cargo] A mechanism for glueing several steppers together, +so that multiple views can share the same center and when one changes, all +change. Details explained in the GZigZag specs. + +\end{description} + +\subsection{Comparison to existing computer structures} + +To put it coarsely, outside \zz\ there are four different kinds of +structures in computers today: linear lists (and grids i.e.~lists of lists), +trees and messes (by +a mess, I mean any complicated data structure). +The first two are inflexible and the third always requires much +programming and debugging to do and is often hard to visualize. + +\zz\ offers a fundamental new kind of {\em structure} where encoding +new structures is simple because the coherence of the underlying +simple flexible structure is guaranteed. +At first it may seem strange that a structure that restricts the +number of connections from each cell can be generic but this simple +restriction is what brings about the coherence of \zz. +In the sections below you'll see how this restriction does not prevent +any structure from being represented using \zz\ but it enables several +clever visualizations. + +\zz\ guarantees that there are no dangling pointers: all links are +two-directional. You can always find which cells refer to a given cell. + +The {\em most} interesting thing about \zz\ and existing structures, +the importance of which I really only realized while doing a demo at Nokia +is simply that by using different dimensions, \zz\ allows you to +arrange the {\em same} things (cells) into {\em different} traditional +structures. So you can have the same cells in a tree along two +dimensions (as you'll see below, trees are easiest done using two +dimensions, one to go from the parent to the first child and the other +to move along siblings), a list along another dimension and a table +along two other dimensions. If you use relcells (see~\ref{sec:relcell}) +you can even put the same things (this time, not cells: you do have to do a step of indirection) +into different structures along the +{\em same} dimensions. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Viewing} + +Now that the structure is defined, we have to be able to view and edit +it on the computer somehow. Of course, we {\em could} just put this +structure in a text file and edit it by naming cells with numbers and +links by naming the cell numbers but this would lose the visuality +inherent in the design. + +There are {\bf many} variations to this theme. For different applications, +different visualizations are of course appropriate but this does not +diminish the fact that underneath all there lies a common structure which +can be visualized in any of the ways, unlike for traditional computer +applications where the structure and the view are usually closely coupled. + +\subsection{Simple 2D raster view} + +A really simple 2D view is obtained by selecting two dimensions and a +``center'' cell. These two dimensions are associated with the X and Y +coordinates and starting from the center cell A, other cells are placed +on a rectangular grid around it, according to the dimensions: let's +say the center cell is placed at coordinates (0,0). Now, if {\tt d.1} +corresponds to X and {\tt d.2} corresponds to Y, and there lies a cell B +poswards from A on {\tt d.1}, then B would be placed at (1,0), and so on. + +Of course, since the \zz\ structure can be paradoxical (it is not +inherently paradoxical in 2D: you can define a structure that looks just +like a spreadsheet), there can be several different cells that would +be typeset at the same point in the 2D diagram. For example, a simple +paradox would be that starting from cell A, going first poswards on {\tt +d.1} and then {\tt d.2} could result in a different cell than first going +poswards on {\tt d.2} and then {\tt d.1}. This is where {\em rasters} +come in. A raster is basically a rule for selecting which cells get +shown in a 2D diagram. There can be several different rasters, from +which the user can select the one best suited for the structure he is +currently viewing. + +The simplest kind of raster, a {\em hard raster} is simply a tree on the 2D +grid: it starts at the center cell and can branch at any cell (including +the center cell) but it will only arrive to each cell once. The cells that +are displayed are chosen by taking exactly those paths that the tree takes +when finding out the cells. If there is no cell in the direction from +the cell being rendered, then that whole branch of the tree is left empty. + +Two rasters, specifically the simplest ones, stand out from among the +possible hard rasters: the horizontal and vertical raster, where the +tree is formed by a single column or row, each cell in which branches +into each row/column. XXX + +\begin{figure} +\caption{The two most common hard rasters. a) row-oriented, b) column-oriented. +Both are shown on a $5\times5$ cell screen.} +.PS +[ +boxwid=0.15; boxht=0.15 +linewid=0.3; lineht=0.3; +up; +C: box; arrow; B: box; arrow; A: box; +down; +move to C.s; arrow; D: box; arrow; E: box; +copy thru % move to $1.e; right; arrow; box; arrow; box; move to $1.w; left; arrow; box; arrow; box % until "END" +A +B +C +D +E +END +] +.PE +a)\box\graph +.PS +[ +boxwid=0.15; boxht=0.15 +linewid=0.3; lineht=0.3; +right; +C: box; arrow; B: box; arrow; A: box; +left; +move to C.w; arrow; D: box; arrow; E: box; +copy thru % move to $1.n; up; arrow; box; arrow; box; move to $1.s;down; arrow; box; arrow; box % until "END" +A +B +C +D +E +END +] +.PE +~~~~~~b)\box\graph +% a) +% \xymatrix @*[F-] { +% & \ar[l] & \ar[l] \ar[r] & \ar[r] & \\ +% & \ar[l] & \ar[l] \ar[u] \ar[r] & \ar[r] & \\ +% & \ar[l] & \ar[l] \ar[u]\ar[d] \ar[r] & \ar[r] & \\ +% & \ar[l] & \ar[l] \ar[d] \ar[r] & \ar[r] & \\ +% & \ar[l] & \ar[l] \ar[r] & \ar[r] & \\ +% } +% ~~~~~b)\xymatrix @*[F-] { +% & & & & \\ +% \ar[u] & \ar[u] & \ar[u] & \ar[u] & \ar[u] \\ +% \ar[u]\ar[d] & \ar[u]\ar[d]\ar[l] & \ar[u]\ar[d]\ar[l]\ar[r] & \ar[u]\ar[d]\ar[r] & \ar[u]\ar[d] \\ +% \ar[d] & \ar[d] & \ar[d] & \ar[d] & \ar[d] \\ +% & & & & +% } +\end{figure} + +A {\em soft raster}, on the other hand is one that does not specify explicitly +how to traverse the cells --- it only specifies how to resolve conflicts +between the cells that would be displayed on the same position and in +which order to ``expand'' cells. A soft raster generally results in more +cells being displayed than a hard raster. An example of a soft raster +would be ``each new cell is expanded; preference is horizontally from +center, vertically from center, horizontally away from center, vertically +away from center''. Incidentally, this soft raster always shows exactly +the same cells at exactly the same positions as the row-oriented raster, +except that it can also show more cells that would have been left out +in the hard raster. + +In order to look clear to the human observer, visual cues about the +structure are vital. All neighbouring cells that lie next to each other +should be connected with a line, and all cells that have neighbours +that were not displayed because of the raster should have e.g. half of a +connecting line, disappearing underneath the other cell in some visual +fashion to show this. Also, when moving in the structure so that the +part of + +\subsection{``Vanishing'' view} + +The vanishing view is a computationally simple way to display 2-4 (or more) +dimensions of the structure. +First, a direction vector is defined for each dimension - for the usual X, Y and Z +they would be (1,0), (0,1) and (1,1). Then, we place the cursor cell at the +center of the screen at size one. We see whether which neighbours exist and +move to the appropriate directions but --- here comes the big innovation --- +we shrink both the size and the direction vectors by multiplying them by 0.9. +Then the process is continued from the last rendered cells, always shrinking. + +In reality, of course, the cells are buffered and rendered in the other direction +since we want the center cell to be on top (and the cells near the center to be +above the ones far from it). + +Other effects may also be applied to clarify the view for the user, such as +graying out the ``far-away'' cells (this is generally called Fog in computer +graphics), thickening the lines of the cells near the center and so on. + +In this view it is important to not render the same cell twice as that would get +even more confusing than with grid rasters. + + +\subsection{Multicentrics} + +\subsection{3D view} + +3-D rastering can be performed in just the same way as 2-D rastering +and visualized by drawing balls and sticks in a 3-D scene. + +XXX + +\subsection{Tree view} + +Since the 2D plane of the \zz\ structure can be viewed as a tree (starting +with 4 branches and branching further at each cell to 3 directions) why +not show it as one? Those places where the structure is not paradoxical +can be shown as regular grids but for the other places, a tree centered +on the home cell and extending outwards can be a good visualization. +The benefit of this view is that it shows {\em all} cells within a +certain range of the center cell --- on the other hand, some of them +may have to be drawn very small, depending on the paradoxicality of +the structure. + +\subsection{Animated cloud view} + +Each dimension has a 2-D vector associated with it and starting from +a given cell, all cells to a given radius are plotted (though not more +than once, even when reached through different paths). +If the vectors are shrunk when going farther from the origin, a view +related to the tree view is obtained. + +Animation and randomity is essential: when this structure rotates, it is +possible to grasp the structure close to a cell. + +\subsection{Pseudo-3D view} + +This view closely resembles a rastered view, except that between the +cells in the grid there are diagonally shown two cells, one poswards +and one negwards of each cell in a third dimension. The connections from +these cells are not shown (but it is shown that they do have connections). + +\subsection{Special, application-oriented views} + +To be correct, instead of application we should use the word {\em +applitude} to distinguish from the traditional kind of monolithic +application. + +For some applications (again: not programs, but rather ``things you do +with \zz''), it is useful to have special views for themselves. This +could include showing some cells from more dimensions around the center +cell than the generic view could do. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Sample structures} + +This section shows some of the possible applications of \zz. +Note that these applications are not applications as in +separate executables that are run to perform a task: that is +old-fashioned thinking. The \zz\ way is to have them all together, +in the same space. This is what Ted Nelson means when he speaks about +applications being prisons: here you can easily link together your +CDs and your pre/reprints and your meetings. + +There is an interesting phenomenon associated with inventing applications +for \zz: when you are first introduced to it, you are astonished at the +things you could do with it but when you start thinking of sample applications, +you may soon draw a blank. + +Interestingly, the reason is likely not to be \zz, but rather the fact that +we have for a long time been trained to think in traditional computer +paradigms and ``paper simulators'' that it is initially hard to see how +the freer multidimensional structure of \zz\ could be of use but slowly, +as you get used to the idea, possible uses will start popping up. +Thinking outside the box is not at all easy. + +\subsection{A CD Player} + +One quite interesting application of \zz\ would be a CD player. +The point is that you can manage the CDs you own, form different +lists of songs on them that you like or that fit particular styles, +download some of them into MP3-files and so on. And play CDs, of course. + +\begin{figure} +\caption{Some view of the suggested CD player structure. +a) The CD player cell, linked to the disk that is in the CD bay and playing +a piece. +The duration along {\tt d.1} is shown only for one piece. +Some of the songs have been cloned and linked to form a short playlist +of my very favorite songs. +\label{fig:cdplayeri} +} +a) \xymatrix@R=0.4cm @C=1.5cm{ +*+[F]\hbox{CD Player} \ar[r]^{\tt d.playing} \ar[rdddd]^{\tt d.playing}& +*+[F]\hbox{Astor Piazzolla / Oblivion} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Jeanne y Paul} \ar[d]^{\tt d.ondisk} + \ar[ddddddr]^{\tt d.clone} + \\ +& *+[F]\hbox{En penultimo} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Oblivion} \ar[d]^{\tt d.ondisk} \ar[r]^{\tt d.1} + & *+[F]\hbox{4:02 XXX} \\ +& *+[F]\hbox{Enrico IV} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Tanti anni prima} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Remembrance} \ar[d]^{\tt d.ondisk} + & *+[F]\hbox{Very best of Oblivion} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Cavalcata} \ar[d]^{\tt d.ondisk} + & *+[F]\hbox{Jeanne y Paul} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Baires '72} \ar[d]^{\tt d.ondisk} + & *+[F]\hbox{Oda para un hippie} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{Oda para un hippie} \ar[d]^{\tt d.ondisk} \ar[ur]^{\tt d.clone} + & *+[F]\hbox{Fuga} \\ +& *+[F]\hbox{Fuga} \ar[d]^{\tt d.ondisk} + \ar[ur]^{\tt d.clone} \\ +& *+[F]\hbox{Homenaje a Cordoba} \ar[d]^{\tt d.ondisk} \\ +& *+[F]\hbox{En 3x4} \\ +}~~~~~ +\end{figure} + +A part of the structure is shown in Fig.~\ref{fig:cdplayeri}. +There would be one cell, representing the CD player. +Each CD would have its own headcell, containing the CDDB id (or some other +type of checksum by which a disk can be identified). +This cell would be linked to the track cells via {\tt d.ondisk}, which +would be linked to the track +names and lengths via {\tt d.1}. + +When the CD player is playing a piece, it is automatically connected +to one of the disk cells via {\tt d.playing} and one of the track +cells of that disk via {\tt d.playingtrack}. The time is shown +by some other (editable!) cells connected to the CD player cell (not shown here). +If there is a CD changer, +there could be also a dimension {\tt d.inbay} which would link the CD +player to all the disk cells of the disks in the changer. +And of course, you could make the player play a different track by +changing the link of {\tt d.playingtrack} or {\tt d.playing}. + +Now that the structure is defined, we can use it either through +the usual views, or through a special view adapted to this +purpose. + +But the most important thing is that now, unlike in most CD player +applications, even the ones that support CDDB, you can now include +your {\em own} information in this structure. The CD player code +would not mind additional connections to the track cells. +It would then be easy to make a note of (and find it again) on which +of the 60 Bach's Kantatenwerk CDs (there are 10 volumes of 6 CDs each) +that wonderful trio between the oboe d'amore, viola da gamba and continuo +was again. + +Alternatively, you could make playlists using clones along {\tt d.clone} +of the track cells, and linking them along {\tt d.ondisk}, creating +a virtual disk for the CD player. + +This kind of interface where some of the connections are ``magical'' i.e. +where changing the connection causes something to happen, and some are +not magical, is a good example of how \zz\ can be used. +Nice graphical interfaces can now be written on top of this structure +but having the simple underlying structure (like an API, except +data-, not code-based) makes it possible to link all the information +provided by the CD player to other applications. The CDDB entries have +been liberated from the prison of the CD player. + + +\subsection{Managing a collection of virtual pre/reprints} + +In academia, you often collect stacks and stacks of pre/reprints +from colleagues, which are quite difficult to keep properly organized +so that when you search for the information you remember you had +at one point it may take quite a while to find it. + +Computers have brought this problem to a completely different level: +nowadays pre- and reprints are often distributed as compressed postscript +files, and often with non-descriptive names like {\tt aaai1.ps.gz} (which +is descriptive to the author but not to others). +Unless you meticulously rename the files to include the author and +the subject, you will before long be hopelessly lost among virtual +stacks of files --- and there you won't even have the same help from +our intuitive understanding of physical space that you would have had +with physical documents. Also, it's slower to scan compressed postscript +files: it takes a few seconds for the computer to show the first page. + +This is one place where \zz\ can truly help. First of all, you can +organize your preprints in lists according to authors and journals. +You can annotate the files. +But most importantly, after doing this, you can browse them easily +using all the available \zz\ viewers. +And not only this: if you are doing your own academic projects in \zz\ as +well, you can link the relevant publications directly to the area +where you are doing your work. + +You could use a database application for this but they are often clumsy +when entering data and the browsing is not even nearly as simple as in +\zz. + +Of course, this problem is caused by not using reasonable data formats +to start with but this is what we have to work with today. + +Maintaining a similar structure e.g.~in HTML would be a nightmare: +dangling links everywhere etc. \zz\ makes it easy since all links are +2-directional and the structure is easy to edit. + +\subsection{Managing program settings} + +Having programs that allow the user to customize their look and functionality +is great. However, one pet peeve of mine is that these programs often +only allow one set of default settings. If I like to have the program to have +one look in a particular context (e.g.~when doing short documents) +and another in some other context (books), I would always have to click through +the configurations dialog and change the settings. + +Even more horribly, many X11 programs take their configuration from +X resources which are specified by name. Here it is possible to have +different configurations for the same program but they are difficult to +edit and even more difficult (or impossible) to change while the program +is running. + +\zz\ can change all this. Because of the ubiquitous data structure, +a program instance (for example, a view window showing a part of the \zz\ +structure) can be given one settings cell. Starting from this cell, the +program will use prespecified paths to find its configuration information, +all in the \zz\ structure. There are three main benefits: +1) this allows several different configurations +for the same program to coexist, 2) if the prespecified paths are done +in a smart way, configurations can ``inherit'' settings from one another +dynamically and 3) the configuration is simple to change at run time because +of the active notification properties of \zz. + +Since the relationship between the configuration property names and values +is like a list, using {\tt d.1} between the property name and value +and {\tt d.2} to link the properties is natural. +For inheriting properties, we'll just use all cells that have a connection +negwards on {\tt d.inheritsettings}. Fig.~\ref{fig:progset} shows this +structure. + +\begin{figure} +\caption{ +A structure useful for program settings. There are three sets of settings +for the program now, represented by the cells Default, MySpecial, and MyUsual. +Both MySpecial and MyUsual inherit most of their settings from Default but +nothing from each other. +\label{fig:progset} +} +\xymatrix@R=0.4cm @C=0.4cm{ +& & *+[F]\hbox{MyUsual} \ar[d]^{\tt d.2} & & *+[F]\hbox{MySpecial} \ar[d]^{\tt d.2}& \\ +& & *+[F]\hbox{BgColor} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2}& *+[F]\hbox{blue} & *+[F]\hbox{Font} \ar[d]^{\tt d.2}\ar[r]^{\tt d.1} & *+[F]\hbox{weirdsym} \\ +& & *+[F]\hbox{FgColor} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2}& *+[F]\hbox{yellow} & *+[F]\hbox{Animation} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2}& *+[F]\hbox{no} \\ +*+[F]\hbox{Default} \ar[d]^{\tt d.2} \ar[rr]^{\tt d.inheritsettings} & & *+[F]\hbox{~} \ar[rr]^{\tt d.inheritsettings}& & *+[F]\hbox{~} \\ +*+[F]\hbox{BgColor} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2} & *+[F]\hbox{white} \\ +*+[F]\hbox{FgColor} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2}& *+[F]\hbox{black} \\ +*+[F]\hbox{Font} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2}& *+[F]\hbox{Times} \\ +*+[F]\hbox{Title} \ar[r]^{\tt d.1} \ar[d]^{\tt d.2}& *+[F]\hbox{ZZ Window} \\ +*+[F]\hbox{Animation} \ar[r]^{\tt d.1} & *+[F]\hbox{yes} \\ +} +\end{figure} + +\label{sec:appconf} +But now there is a small potential problem: what about misspellings? +If I were to write {\tt bgcolorr} instead of {\tt bgcolor}, the +setting would be quietly ignored. +This is where the fact that \zz\ is a {\em structure} can be incredibly +helpful. Instead of creating new cells with the setting names, we simply +{\em clone} the cells representing the setting names. This can make +our life even simpler if the same cells are used in the documentation: +when you want to change a setting, you simply clone the correct cell +from the documentation, add it to the setting list and write in your setting --- +and of course this process can be automated with a small script. +As a bonus, you'd get a listing of all your settings for a given setting +by simply browsing the structure. +This is not shown as a figure because drawing this in 2D without interaction +and animation is difficult. + +Another place where the structure and links of \zz\ are wildly useful +is font management. It's possible to have a master font list from where +you can clone fonts to smaller, private lists where the fonts you like +are easily accessible and finally clone them to the settings list, +without having to remember the whole name or without having to always +pick the fonts from the long lists of possibilities. + +Due to the generic nature of \zz, the applications of this idea are +not at all limited to program settings. +The same kind of arrangement can naturally work for key- (and mouse-) +bindings as well, +where the setting would be a script that would be run when the key +is pressed. +Another application of this paradigm would be controlling parameter sets +to scientific computations. + +\subsection{Keybindings} + +There is another type of structured information that is generally +rather difficult to manage: keybindings. Most programs fix their keybindings +absolutely, allowing for no customization. Some programs allow the user +to choose which key does what but won't allow multiple states or such. + +In ZigZag, implementing keybindings is ridiculously simple: we simply +define a traversal algorithm that performs some action every time a key +is pressed. The state can be specified by a cursor-like construction. +For example, +\begin{enumerate} +\item 1. +Start from the current cell and move down on {\tt d.2} until a string +matching the keystroke is found. If not found, return. +\item 2. +Move one step on {\tt d.1}. This is the cell giving the name of the action. +Execute action, downwards on {\tt d.2} from here. +\item 3. +Move to the poscell on {\tt d.3} from the action-name cell. +Set the next state to be this. If there is no rank on {\tt d.3} from +the action-name cell, return to the original state. +\end{enumerate} +Additionally, the algorithm can be made to traverse rule sublists +listed on {\tt d.3} from a cell on the action dimension. + +The more mathematically oriented readers will have recognized this +as being a simple state machine --- which is exactly what it is. +The point here is simply that it is easy for the user to edit this state +machine using the ZigZag tools. + + +\subsection{A better {\tt javadoc}} + +Javadoc is the tool used to produce hypertext (in the ``traditional'' sense) +documentation by extracting on-line documentation from java source code +and adding links to the classes of the parameters etc. +This type of documentation is quite useful, giving the programmer +the ability to quickly jump to definitions of related classes. + +Here, however, \zz\ has a lot to give. The problem with javadoc is that +it produces HTML files which are read in a browser which does not understand +the structure of the documentation. Browsing through the package hierarchy +must happen through clicking on links and the back button. + +In \zz, it is easy to handle tree structures + + +\subsection{A personal information manager} + +\subsection{A programmer's editor} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Designing structures} + +There are as many different structures as applications but still there +are some helpful design patterns for \zz\ structures just as in OOP. + +\subsection{Arrangement along a dimension} + +Sometimes, there is a good, unique way of arranging cells along a +dimension, e.g.~alphabetical order. However, sometimes there is not, +or there are two different orders you'd like to have. + +This may seem like a difficult problem but actually, if all but one of the +desired orders are easy to determine from the neighbours of the cells, +then there is no problem at all: instead of expressing it directly in +the structure, those orderings that are easy to construct algorithmically +should be delegated to the view (as of yet, there are no viewers capable +of this but they are under construction). + +This idea applies to the clones and many to one reference sections below. + +If you really need several arrangements, you could consider +a second dimension along which to arrange the same cells, or alternatively +cloning the cells for another arrangement, or even putting dummy cells +next to the cells in some other dimension with the sole purpose of +arranging the cells (this is something that could be done to simulate +email folders so that the same piece of email can be in several +folders at once). + +\subsection{Clones} + +When designing e.g.~an email application, the same person will pop up +often in the correspondence. One good way of keeping track is to have +all the references to the person be clones i.e.~cells having the exactly +the same content, connected to each other along {\tt d.clone}. The head +cell is the ``original one'' into which you'd store other facts about +the person. + +Similarly, clones were suggested for the cells used to name +settings in the example in Sec.~\ref{sec:appconf}. + +\subsection{Many to one reference} + +Having many cells refer to one cell may be conceptually difficult in +\zz\ at first due to the fact that each cell may only have one link +in one dimension. However, this is possible through either clones +or headcells. + +Remember that there is only one headcell per rank --- why not organize all +the cells that refer to the one cell as a rank and have the headcell of +the rank be the cell linked to? It is possible to define special rasters +that take this into account. + +The reason this is better than having many cells referring to one cell +directly by a pointer or something is that now it is easy to ask the +inverse question ``which cells refer to this cell''. The structure is +much more robust because of this: there will be no dangling references, +i.e.~a cell can't be deleted without knowing that there is a link from +somewhere to it. + +In Sec.~\ref{sec:appconf} the dimension {\tt d.inheritsettings} was +used like this: two settings were able to inherit the same set of +settings by defining the headcell in {\tt d.inheritsettings} to be the +settings to be inherited. + +See also the next subsection for a structure for expressing general +relations. + +\subsection{Relation Cells} + +\label{sec:relcell} + +Relation cells (relcells) are a commonly occurring construct in \zz. +Fundamentally, relcells exist to declare a relationship between two +cells or two groups of cells. + + +% .PS +% copy thru % circle at ($1,$2) % until "END" +% 1 2 +% 3 4 +% 5 6 +% END +% box +% .PE +% +% \centerline{\raise 1em\box\graph} + + + +\begin{figure} +\caption{ +\label{fig:relcell} +a) A simple relation cell , marked with a $+$, connecting two cells +to each other. +b) The reason for such relation cells: A is related to C and D but B is +only related to C. This kind of relation is not specifiable without relation +cells. +} +a) +.PS +box "A" +arrow "d.x" "" +box "+" +down; move to last box.s +arrow "d.y" ljust +box "B" +.PE +\box\graph +b) +.PS +box "A" +arrow "d.x" "" +RC1: box "+" +arrow +box "+" +down; move to last box.s +arrow down 1 +box "D" +move to RC1.s +arrow +RC3:box "+" +arrow +box "C" +move to RC3.w +left +line <- +box "B" +.PE +\box\graph +% a) \xymatrix{ +% *+[F]\hbox{A} \ar[r]^{\tt d.x}& *+[F]\hbox{+} \ar[d]^{\tt d.y} \\ +% & *+[F]\hbox{B} +% }~~~~~ +% b) \xymatrix{ +% *+[F]\hbox{A} \ar[r]^{\tt d.x}& *+[F]\hbox{+} \ar[d]^{\tt d.y} \ar[r]^{\tt d.x} +% & *+[F]\hbox{+} \ar[dd]^{\tt d.y} \\ +% *+[F]\hbox{B} \ar[r]^{\tt d.x}& *+[F]\hbox{+} \ar[d]^{\tt d.y} \\ +% & *+[F]\hbox{C} & *+[F]\hbox{D} +% }~~~~~ +% c) \xymatrix{ +% *+[F]\hbox{A} \ar[r] +% } +\end{figure} + +As shown in {\tt fig:relcell}, +the basic relcell denotes an association between one endcell of one dimension +and another endcell of another dimension. + +This is not the only kind of relcell there is: a different type is +one that relates many cells to one, in such a way that many different +sets of cells can be related to the same cell. This kind of relation +is useful for e.g.~cursors. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Programming \zz} + +This section explains how scripts can be used in \zz. Also, +we discuss how the view applications can be made simple +through clever use of scripts. + +\subsection{The scripting API} + +The most basic operations in \zz, expressed with parameters +\begin{description} +\item[new cell(cell, dim, posneg)] Create a new cell from the given cell in the given +dimension, in the given direction. +If a cell already exists in that direction, insert this new cell between +the current cell and the existing cell in the same rank: +the rank ABCDE, if the new cell n is inserted poswards from C, +becomes ABCnDE. The other connections from all cells are unaffected. +\item[delete cell(cell)] Delete the given cell. +\item[link(fromcell, tocell, dim)] Create a connection between fromcell and tocell along dimension +dim. +\item[delete link(cell, dim, posneg)] Delete the link from the given cell in the given dimension +and direction. +\item[set cell contents(cell, data)] Set the contents of the cell to data. +\end{description} +In a visual environment, you give the parameters by clicking etc. but the basic +operations are still the same. + +Now, these are the absolute minimum operations to get by: they are +definitely not a complete set of useful operations. +All the advanced operations can be defined through these operations, though. + +There are a number of more complicated editing operations that deal with ranks: +\begin{description} +\item[jump(cell,dim,posneg)] In its rank on dimension dim, hop this cell over its neighbour. +The rank ABCDE, if B is jumped poswards, becomes ACBDE. No other connections from the cells are affected. +\end{description} + +XXX Shearing + + +\subsection{Scripts} + +Currently, a cell with a \verb+#+ sign in front of it can be +interpreted as executable code. The code gets as its parameters +the cell the code was in and one parameter cell (possibly also a +cell representing a viewer in the future). + +\subsection{Editing via scripts} + +The interface to edit the \zz\ structure in our prototype is encoded +mostly in terms scripts: the only operation the viewer knows about +is executing one cell on another cell. The viewer does not know how +to e.g.~create a new cell or link cells. + +This gives us a surprising amount of flexibility in the user interface. +For instance, if we want to have a {\tt Skip to} operation in our +CD player, we can simply write a small script in a cell that finds +the CD player that is playing the disk and connects it along the +{\tt d.playingtrack} dimension to the cell the {\tt Skip to} script +was executed on. We can then bind either tell the viewer to execute +this action or even specify a special binding for it in the viewer +configuration (which is also stored in the \zz\ structure). + +\subsection{Watches} + +(DRAFT!) +It is possible to place scripts in the structure which are run whenever +some part of the structure is changed. This is how the CD player example +above would be implemented. +This is a very simple mechanism: the scripts are placed along a +dimension {\tt d.watch} from the cell which (and the connections of which) +are being watched. Whenever the cell or one of its connections is changed +or deleted, the scripts are run. + +XXX watching a watcher? + +\section{Versioning} + +NB. This section is subject to change. It is meant to be a sketch for +implementing versioning for \zz\ and is by no means final. +This is currently not yet implemented. + +Normally, on computers, if you edit a file and save it, the previous +version is gone. You have changed the contents of the file and now the +new contents is all you can see. There are programs, like RCS and CVS, +that can be used to store and track the changes to a single file or to +a group of files. There are even versioning filesystems where you +are able to retrieve the previous versions of your files. + +In \zz, versioning is inherent in the structure: the previous versions +are accessible through simply browsing the structure itself. + +In \zz, there are two kinds of storage for cells: transient and permanent. +Cells in transient storage are treated just like normal files: when +they are deleted they are gone, or when they are changed, the previous +form is not accessible. This is what is currently being implemented in +our prototype. + +Permanent cells (the recommended type of storage in the future) are +a more interesting case: when you delete a permanent cell, you are +actually only deleting all the links to it --- or more accurately, you +are creating a new version of that cell and all its neighbours, and in +this new version, the connections between the cell being ``deleted'' +and its neighbours do not exist. Nothing is deleted from the storage; +only information about the changes is added. In permanent storage, it is +possible to access all the previous versions of any part of the structure. + +The parts of the structure that deal with versions are a good example +of {\em virtual cells}, which you can view and sometimes (depending +on the context) alter or at least link to, but which do not necessarily +exist in the same way as ordinary cells but are generated on the fly +by the \zz\ server from the information it has. + + +\subsection{Cell Identity} + +In order to distinguish between different versions of a cell, there are +two different types of cell ids. The LID (Lifespan ID) refers to all the +versions of a cell at the same time, i.e.~it refers to one rank in the +dimension {\tt d.cellversion}. The posend of that rank is the current +version of the cell. The VID (Version ID) refers to one particular +version of the cell, i.e.~that cell at all moments between two changes +that occurred to that cell. + +The {\tt d.cellversion} dimension is generally not what you want to use +since it tracks changes to that one cell only. It jumps right over any +changes to a neighbouring cell or any other cell. + +The {\tt d.version} dimension is another versioning dimension. This is +the global version, which changes for every cell when even one change +is made anywhere in the structure (a number of changes may be committed +simultaneously though). + +\begin{figure} +\caption{An example of how {\tt d.version} works. +In this example, we start with two cells, A and C. First, a new cell B is created +on {\tt d.1} from A, and then this new cell is connected to cell C and finally a new cell +D is created negwards on {\tt d.1} from A. +The straight arrows show {\tt d.globalversion} horizontally and {\tt d.1} vertically. +The curved arrows show {\tt d.cellversion}. Note how they skip several of the global versions +since nothing happened to that cell. All the connections along {\tt d.cellversion} are shown, +so it is important to notice that there is no neighbour in that dimension for many cells, only +the {\em last} cell representing each cell version. +The cells are vertically aligned by time. +Also, note that if there were more cells and they had been changed, there would be one more step +in {\tt d.globalversion} for each change not visible here. +} +\xymatrix{ +& & & D \ar[d] \\ +A \ar[r] \POS"2,3"**\crv{[]+(20,20)}?>*\dir{>} & A \ar[r]\ar[d] +& A \ar[r]\ar[d] \POS"2,4"**\crv{[]+(10,20)}?>*\dir{>} +& A\ar[d]\\ + & B \ar[r] & B \ar[r] \ar[d] & B \ar[d]\\ +C \ar[r] +& C \ar[r] \POS"4,4"**\crv{[]+(20,20)}?>*\dir{>} +& C \ar[r] & C\\ +} +\end{figure} + +\subsection{Scrolls} + +One of the fundamental concepts in the Ted Nelson's Xanadu system is that +of {\em scrolls}. A scroll is a storage form of data into which new data +is appended but old data is never removed --- it is essentially carved +in stone as it arrives. The data in scrolls is used by pointing to it. + +%%%%%%%%%%%%%%%%%%%% +\section{Distributed \zz} + +Like the section on versioning, this section is at best a raw sketch +of the functionality. + +\subsection{\zz\ remote protocol} + +In order to allow different \zz\ processors to interact, we have +defined a \zz\ data protocol. The protocol is an active one and has +state --- so it is more suitable between processes on the same machine. +A passive, stateless protocol is under planning. + +The protocol allows a client to be informed whenever any cell changes +(the client has to explicitly request to be informed about a cell, though), +change the structure, or run code. + +The protocol is still not finalized. + + +\subsection{Slices} + +There can be several different data sources: for instance, files on a disk +could be represented by a process that serves \zz\ cells through looking +at the filesystem, or \zz\ structures from different computers on a network +could be represented as data sources. + +In general, all different sources of data in the sense that they provide +a collection of \zz\ data are called slices. + +\section{ZZ Programs} + +So far, we have been talking about \zz\ on a fairly abstract level. In +this section, we'll start looking at some implementation details that +make \zz\ special. + +\subsection{Model-View-Controller} + +The Model-View-Controller (MVC) paradigm was introduced with SmallTalk. +The idea is that instead of programming a graphical program like spaghetti, +you'd clearly separate the data that is being represented, the views +of the data and whatever changes the data (the controllers). +The view and the controller are usually a part of the same object, so +that you can e.g.~drag pieces of a diagram but the point is that the +view and the controller do not communicate with each other. +The controller changes the model and then {\em all} the different views +get updated as well. + +The Model in \zz\ is of course the \zz\ structure. +Changing the raster would be achieved {\em not} by changing some +internal variable of the graphical client but rather by changing the +part of the \zz\ structure that represents the client. +Likewise, the cursors of the various views are represented in the structure +as are the selected dimensions and rasters. + +In the \zz\ system, using a MVC structure pervasively has many benefits. +First and foremost, it brings configuration and run-time data of +the \zz\ programs to the same area as the other data. This way +all the facilities of \zz\ for scripting and editing can be used +for these as well. As an example, writing a small script that finds +the next {\em relevant} dimension to show in X direction is trivial +when all the data is in the \zz\ structure but doing the same if the +application were built in a traditional way is next to impossible --- or +at least difficult, requiring a special API provided by the application. + + + + + +\end{document} + + diff --git a/Documentation/Glossary/Makefile b/Documentation/Glossary/Makefile new file mode 100644 index 0000000..404b0c8 --- /dev/null +++ b/Documentation/Glossary/Makefile @@ -0,0 +1,10 @@ +# DIAGRAMS=linkorder.png beamorder.png +DIAGRAMS=../wmlinc/article.wml + +all : gl.html gl-ns4.html + +gl.html: gl.wml $(DIAGRAMS) + +gl-ns4.html: gl.wml $(DIAGRAMS) + +include ../lib.mk diff --git a/Documentation/Glossary/gl.wml b/Documentation/Glossary/gl.wml new file mode 100644 index 0000000..f518d09 --- /dev/null +++ b/Documentation/Glossary/gl.wml @@ -0,0 +1,186 @@ + + + + + + GZigZag Glossary + +#include '../wmlinc/article.wml' + + + + + +

GZigZag Glossary

+
$Id: gl.wml,v 1.3 2000/09/19 10:31:57 ajk Exp $
+ + Tuomas Lukka
+ lukka@iki.fi
+
+ +

+This is a short glossary of terminology related to GZigZag. +Only a short definition of each term is given, possibly with +a reference to more material on the subject. + + + +


+
+
ZigZag structure / space +
A simple structure, based on cells and dimensions + which the user is able to easily shape into any desired + structure. All interrelated pieces of information can be + close to each other on some dimension. +
cell +
The smallest unit of information in ZigZag. + A cell can contain a text string or + a single span in a permascroll; the separation is + because a text string can be edited but a span can only + be lengthened or shortened: no characters can be + inserted. Cells are connected to each other along + dimensions. +
dimension +
Connecting cells along dimensions is what ZigZag is + about. Locally, dimensions work just like on a spreadsheet: + each cell can be connected to one cell in the positive + direction and to one cell in the negative direction + along each dimension. However, there are no global constraints + between the dimensions. + +
headcell +
The negend of a rank, or, for + circular ranks, a specially designated cell. + If a rank of cells has one "special" cell, then + it is usually the headcell. + + +
neighbour +
Cells that are connected along a dimension are + called each other's neighbours. Often, the term + posward or negward is used with this term as in + "the negward neighbour on d.cursor". + +
posward/negward +
In the positive/negative direction along a rank. + +
posend/negend +
As far as you can go negwards or poswards. + Circular ranks have no ends. + + +
rank +
A rank on a dimension D is simply a set of cells that are + connected to each other on D. A given cell can only + be on one rank on a given dimension. + +
raster +
A set of cells selected from the structure + by a set of rules, for visualization. + For example, the row and column raster select, + starting from the cursor, + a single rank in one dimension + an all ranks in another dimensions that + intersect that rank. + The raster for the vanishing view selects all + cells within a given radius of the cursor. + +
relcell, or relation cell +
A cell which exists not for its content but for + expressing a relationship between other cells. + For example, the cell between a father and mother + in the family tree demo is a relcell. + +
row/column +
These words simply correspond to ranks + being viewed horizontally/vertically. + They do not mean anything in the abstract structure, + but only in the visualizations. + +
view +
A way of placing the cells in a particular + raster on the screen. + +
+
+
+ +
FloatingWorld +
Ted Nelson's design built on top of ZigZag structure, + based on flobs. +
flob +
A multi-dimensional flying object. That is, an entity + representing something that may have any number of + flob coordinates. For example, an email's sender is one + flob coordinate, its subject another. + +
+
+
+ + +
Xanadu88 +
A hypertext system, finished in 1988, which works by + stable fluid media content instead of URL-like pointers. +
fluid media +
Any media types that can be subdivided. + Text, audio, video, images. +
permascroll +
A storage philosophy for fluid media where + each smallest unit (e.g. character of text) + is assigned a permanent identifier when + it first enters the system. Of course, + references to the smallest units usually happen + through spans for efficiency. +
span +
A (reference to a) contiguous section of the permascroll. +
vstream +
A list of spans that describe a virtual stream of + fluid media. A "document" or one version of a document. + Modifying a document does not modify the permascroll, except + by appending new inserted characters. Instead, the spans + of the vstream are modified: split apart, new spans + inserted etc. +
transclusion +
The inclusion of the same material in a permascroll in + two different documents. One of the fundamentals of the Xanadu88 + model is that it is efficient to search for transclusions + of a given span. +
transpointing windows +
Windows on a computer screen that show the connections or + transclusions between each other. + +
transcopyright +
A copyright scheme where the copyright holder + grants the public a permission to refer to any + portion of a given document and publishes the document + in a permanent location. + This way, anyone can quote the document by referring + to it and the reader's browser will then go to the + originator's server for the original material so that + a micropayment can be made to the original author + of the material. +
+ +
+ + + + + + diff --git a/Documentation/Interfacing/Makefile b/Documentation/Interfacing/Makefile new file mode 100644 index 0000000..f802aa5 --- /dev/null +++ b/Documentation/Interfacing/Makefile @@ -0,0 +1,6 @@ +int.dvi: int.ptex + gpic -t int.tex + latex int.tex +ps: int.ps +int.ps: int.dvi + dvips int diff --git a/Documentation/Interfacing/int.ptex b/Documentation/Interfacing/int.ptex new file mode 100644 index 0000000..55191ee --- /dev/null +++ b/Documentation/Interfacing/int.ptex @@ -0,0 +1,141 @@ +% MAKE SURE YOU EDIT THE RIGHT FILE, int.ptex and not the int.tex +% file where gpic has already expanded things. +\documentclass{article} + +\usepackage{rcs} +\RCS $Date: 1999/12/23 01:53:35 $ +\RCS $Revision: 1.3 $ +\date{Rev.\RCSRevision~~\RCSDate} + +\title{Interfacing ZigZag with ``normal'' programs} +\author{Tuomas J.~Lukka} +\begin{document} +\maketitle + +\def\zz{ZigZag} + +\section{Introduction} + +\zz\ defines a coherent universe of cells and things that happen +when cells are modified and connected to each other. +However, since the computer and windowing system underneath don't know +anything about \zz, there is a level on which the \zz\ abstraction +and ``normal'' programs in e.g.~Java meet, so that \zz\ can be implemented +in e.g.~Java. +Because \zz\ is so different from our usual programming concepts, +an interface like this is not trivial to design correctly and +efficiently. + +While the basic operations are simple, i.e.~get neighbour, connect, +create new cell etc., the handling of the interface in a coherent way +on both sides is not simple. +As an example of the difficulty, consider +keeping a list of some attributes that you want the screen to show. +It doesn't matter what these are attributes of, or how they are shown. +We are concerned with the list itself. + +\section{Model-View-Controller} + +When programming with \zz, the MVC (Model-View-Controller) representation +is a useful abstraction, the point being that all the relevant information +is kept inside the \zz\ space with many different views of the same +data being then possible. + +Let us then expand on the list-of-attributes problem. +The natural representation for a list of attributes +is rank along some dimension +in the \zz\ space, beginning at some designated cell. +Having the list in the \zz\ space gives the system the kind of +programmability and coherence which you won't find anywhere else. +However, this programmability and coherence does not come entirely +free. The trouble is when your e.g.~Java code which actually handles +the drawing on screen wants to use the list. + +Just reading the list with the above operations is easy, you just +start at the designated cell and work your way through the list. +The trouble starts when the user modifies the list. At that point, +the user's expectation is that the display will change accordingly. +So your program should realize that the list changed. + +This can be handled through callback routines but the problem is +keeping the callbacks up to date as well and handling the overzealous +callbacking with grace (e.g. if the user makes many modifications and +some while the system is busy rerendering the graph). + +\section{Synchronization} + +When several concurrent processes or threads are active on the +same \zz\ space, care is necessary to avoid race conditions (as +in all other programming with concurrent streams of execution). + + + +\section{A proposed solution: {\tt d.watchers} and {\tt d..watching}} + +As seems to happen often with \zz, the problems can be partially +solved by moving the system to \zz\ space. +So, why not have two dimensions (see the section on relcells +in the Gentle Introduction) showing the relationship between +nodes representing observers and nodes representing watchers? + +This simplifies things because there will be one cell on the \zz\ side +representing the Java object which is observing a group of cells. +The ``A observes B'' relation is encoded into the \zz\ structure +as in Fig.~\ref{fig-enc} +and makes it possible visualize and {\em debug} what is going on. + +\begin{figure} +\caption{Encoding watching relations in the \zz\ structure. +Watcher A watches both cells 1 and 2 and watcher A only watches +cell 1.} +.PS +A: box "Watcher B" height 0.25 +arrow "\tt d..watching" "" +box "" same +up +move to last box.n +line <- "~\tt d.watchers" ljust +R1: box "" same +right +move to last box.e +arrow +R2: box "" same +move to R1.w +left +line <- +B: box "Watcher A" same +move to R1.n +up +line <- +box "Cell 1" same +move to R2.n +line <- +box "Cell 2" same +.PE +\centerline{\raise 1em\box\graph} +\end{figure} + +Also, the relcells can be put to another use beyond just showing +that there is a relation +in this design: they show the {\em kind} of watching relation, +i.e.~contain a list +of things that the other cell is observing about the observed cell, +such as the content or the connections along some subset of dimensions. +This makes it easier to avoid unnecessary work in the list example +if someone wants to comment (along {\tt d.comment}) on one of +the cells in the list. + +Even more pleasantly, this design will fit in nicely with Clang: +the cell which is observing can just as well be a Clang script. + +\section{Designing \zz-code interfaces} + + + + + + +\end{document} + +% +% vim: set syntax=tex : diff --git a/Documentation/Makefile b/Documentation/Makefile new file mode 100644 index 0000000..3eb5138 --- /dev/null +++ b/Documentation/Makefile @@ -0,0 +1,39 @@ +all: + echo "Use a target" + +docdirs=ApplitudeWriters Clang_Design CyberText DesignProblems Gentle_Introduction Glossary Spec UsersGuide Nile + +distdocs: + set -e ; for d in $(docdirs); do $(MAKE) -C $$d all ; done + +dist: distdir=docdisttree +dist: distdocs + rm -rf $(distdir) + mkdir $(distdir) + ln FAQ $(distdir) + ln index.html $(distdir) + set -e; for d in $(docdirs); \ + do \ + echo -n "mkdir $(distdir)/$$d...";\ + mkdir "$(distdir)/$$d"; \ + echo "done."; \ + files=`find $$d -name \*.html -o -name \*.png`;\ + echo "Copying `echo $$files` to $(distdir)/$$d..."; \ + ln -f $$files $(distdir)/$$d; \ + echo "done."; \ + done + +ps: + (cd CellScroll; make ps) + (cd Clang_Design; make ps) + (cd Gentle_Introduction; make ps) + (cd Interfacing; make ps) + (cd Spec; make ps) + +# Special target for Tjl only ;) +mvps: ps + scp */*.ps tjl@gzigzag.sourceforge.net:/home/groups/gzigzag/www/ps/ +cleanps: + rm -f */*.ps +clean: cleanps + rm -f */*.dvi */*.log */*.xyc */*.pdf diff --git a/Documentation/Math/Makefile b/Documentation/Math/Makefile new file mode 100644 index 0000000..58a4523 --- /dev/null +++ b/Documentation/Math/Makefile @@ -0,0 +1,3 @@ +all : math.dvi math.ps + +include ../lib.mk diff --git a/Documentation/Math/ajk-scribbles.tex b/Documentation/Math/ajk-scribbles.tex new file mode 100644 index 0000000..067adf4 --- /dev/null +++ b/Documentation/Math/ajk-scribbles.tex @@ -0,0 +1,60 @@ +\documentclass{article} + +\usepackage{bbm} +\usepackage{amsmath} + +\newcommand{\N}{\mathbbm{N}} + +\newtheorem{Def}{Definition} +\newtheorem{The}{Theorem}[Def] + +\DeclareMathOperator{\Dom}{Dom} +\newcommand{\Dim}[1]{\tilde{#1}} + +\begin{document} + +Note: we assume here that dimensions are cells instead of strings. + +\begin{Def}[space] +A ZigZag space is the triplet $Z = (X, c, C)$ where $X$ is the set of +cells, $c : X \rightarrow \Sigma^*$ is the cell content mapping +and $C \subset X^3$ is the set of connections, if the following hold: +% +\begin{enumerate} +% +\item If $(d, e, f) \in C$ and $(d, e', f) \in C$ then $e = e'$. +% +\item If $(d, e, f) \in C$ and $(d, e, f') \in C$ then $f = f'$. +% +\end{enumerate} +\end{Def} + +\begin{Def}[subspace] +A ZigZag space $Z' = (X', c', C')$ is a subspace of another ZigZag +space $Z = (X, c, C)$ if the following hold: +% +\begin{enumerate} +% +\item $X' \subset X$ +% +\item $c'(x) = c(x)$ for every $x \in X'$. +% +\item $C' \subset C$ +% +\end{enumerate} +\end{Def} + +\begin{The} + Let $Z = (X, c, C)$ be a ZigZag space. For every $d \in X$, there + exists a maximal $X' \subset X$ and a unique $\Dim{d} : X' + \rightarrow X$ such that for every $x \in X'$ it holds that $(d, x, + \Dim{d}(x)) \in C$. Additionally, $\Dim{d}$ is an injection. +\end{The} + +\begin{Def}[clone dimension] + Let $Z = (X, c, C)$ be a ZigZag space. We say that $d \in X$ is a + clone dimension if, for every $x \in \Dom d$ it holds that $c(x) = + c(\Dim{d}(x))$. +\end{Def} + +\end{document} diff --git a/Documentation/Math/math.ptex b/Documentation/Math/math.ptex new file mode 100644 index 0000000..642318b --- /dev/null +++ b/Documentation/Math/math.ptex @@ -0,0 +1,110 @@ +% Emacs, note: this is a -*- LaTeX -*- file. +% MAKE SURE YOU EDIT THE RIGHT FILE, math.ptex and not the math.tex +% file where gpic has already expanded things. +\documentclass{article} + +\usepackage{rcs} +\RCS $Date: 2000/07/18 05:21:50 $ +\RCS $Revision: 1.3 $ +\date{Rev.\RCSRevision~~\RCSDate} + +\usepackage{amsmath} + +\title{Mathematics of ZigZag} +\author{Tuomas J.~Lukka} +\begin{document} +\maketitle + +\newtheorem{theorem}{Definition}[section] +\newtheorem{definition}[theorem]{Definition} + +\section{Introduction} + +The purpose of this document is to look at ZigZag from a +mathematical perspective. + +It is slowly becoming more and more obvious that this type of analysis +can help us understand some of the conceptually less clear parts of ZigZag +and why they are conceptually less clear. + +\section{Tumblers} + +\section{Definition of a ZigZag space} + +\begin{definition} +% A ZigZag space $Z$ is the tuple $(C, d, t)$ of the set of cells $C$, +% a mapping $d$ from strings to bijections between subsets of $C$, +% and a mapping $t$ from cells to cell contents +% (either permascroll spans as tumbler addresses or strings) +A ZigZag space $Z$ is the tuple $(C, d, t)$ of the set of cells $C$, a +mapping $d$ from strings to the set \( D := \{ \, f\colon $C'$ +\longrightarrow $C''$ \mid \text{$f$ is bijective and } C', C'' +\subset C \, \} \) and a mapping $t$ from cells to the set of all +possible cell content (permascroll spans as tumbler addresses or +strings). +\end{definition} + +Now, special dimensions can be defined simply as restrictions on +the space; for instance, as predicates: +\begin{definition} +The ZZspace $Z$ has a clone-dimension $d_0$ iff +for all cells $c$ for which $d(d_0)(c)$ exists, $t(d(d_0)(c)) = t(c)$. +\end{definition} + +Likewise, we can define a versioning operation: +\begin{definition} +A ZZ operation $o: Z \rightarrow Z'$ is versioning +if ... XXX +\end{definition} + + +\section{Solving real problems} + +\subsection{Slice spaces} + +It is possible to highlight some problems related to defining operations +and combinations of spaces with this type of analysis. One observation +made early on in the coding was that encapsulation makes it complicated +to define operations on e.g.~slice spaces (spaces that consist of a +combination of several spaces). For example, in $C = f(A,B)$ the ZZspace +is $C$ a slice space if it contains cells corresponding to most cells +of $A$ and $B$ (excluding {\em preflets}, i.e. cells whose meaning is to +specify for $f$ which cells are to be connected between $A$ and $B$). + +The forwards transform is simple: $C = f(A,B)$ as above. +However, problems begin to appear when we consider that normally +performing an operation functionally: $A' = \Omega(A)$ causes $A'$ to be +saved on the disk to replace $A$. $C' = \Omega(C)$ cannot do the same +as simply because we would like to trace the chain to change $A$ and $B$, +obtaining $(A', B') = f^{-1}(\Omega(f(A,B)))$. This can naturally be quite +complicated. Most combination functions $f$ used in reality are nice but still +this causes a pronounced difficulty in coding the usual operations +(new cell, etc) on slice spaces if starting from this perspective. + +Thus, the conceptually simplest way forwards might be defining a whole +new kind of mathematical object, a slice space, which has its own +operations that naturally distribute to the next level. +After this it is simple to define performance enhancements by caching parts +of the next level space but the conceptual simplicity of directly modifying +only the underlying representation (instead of e.g.~the representation {\em and} +a cache) is appealing. + +\begin{definition} +A Slice space $S$ is a +tuple $(Z_0, s)$ where $Z_0$ is the slice 0, i.e.~the root space, +and $s$ is a mapping from strings to ZigZag spaces +\end{definition} + +\begin{definition} +A slice composition function +$f_c$ is a mapping +$S \rightarrow Z$ +from a slice space to a ZigZag space (the composition function). +\end{definition} + + + +\end{document} + + + diff --git a/Documentation/Mediaserver/mediaserver.tex b/Documentation/Mediaserver/mediaserver.tex new file mode 100644 index 0000000..6f48700 --- /dev/null +++ b/Documentation/Mediaserver/mediaserver.tex @@ -0,0 +1,387 @@ +% This is a -*- LaTeX -*- file. +\documentclass[a4paper]{article} + +\newcommand{\ra}{\ensuremath{\rightarrow}} + +\ifx\dontdraft\undefined +%Draft +\newcommand{\marginaali}[1]{\marginpar{#1}} + +\setlength{\marginparwidth}{3cm} +\setlength{\textwidth}{13cm} +\setlength{\oddsidemargin}{1.3cm} +\else +%Non-draft +\newcommand{\marginaali}[1]{} +\linespread{1.6} +\fi + +\newcommand{\nakki}[1]{\marginaali{\textbf{\small Nakki: #1}}} +\newcommand{\ajk}[1]{\marginaali{\small ajk: #1}} +\newcommand{\tjl}[1]{\marginaali{\small tjl: #1}} + +\begin{document} + +\title{GZigZag mediaserver (to be renamed!) design} +\author{Tuomas J.\ Lukka \and Antti-Juhani Kaijanaho} +\date{2001} + +\maketitle + +\begin{abstract} +The purpose of the mediaserver is to implement +the Xanadu permascroll model +in an easy-to-use encapsulated fashion. + +The mediaserver incorporates both peer-to-peer and +client-server transfer of data. + +This ties in with Ted's other projects, and the intent +is to produce a simple but powerful system completely independent +of GZigZag (GZigZag is on a higher level and uses this as a library). +(The source code is currently in the GZigZag repository but +we might make a new project out of it at some point) +\end{abstract} + +\begin{verbatim} +$Id: mediaserver.tex,v 1.12 2001/04/03 11:23:58 ajk Exp $ +\end{verbatim} + + +\section{Intro} + +The Xanadu media model is based on attaching a permanent identifier +to each piece of fluid media (e.g. text, audio) entering the system. +This arrangement adds a level of indirection to media access, allowing +content linkage, version comparison of documents composited from +spans of fluid media, and automatic sharing of data between copies. + +Additionally, the Xanadu media model incorporates micropayments: +when requesting a + +The gzz mediaserver is an implementation of these ideas\ldots + +Somewhat like freenet, but encryption is not the point here, point +is media sharing, caching, replication and access. + +\subsection{Digital Rights Management versus Fair Use} + +\begin{itemize} +\item support copying of cached content between the user's machines, but + no large-scale copying without repayment to content originator + +\item voluntary compliance + +\item testing of compliance by requests + +\item give people possibility of doing the right thing + +\item Asserting copyright \ra\ revocation? + The infringer is the one granting access to the material, not the user! +\end{itemize} + +\subsection{For Gzigzag} + +If we want to include a piece of audio into a ZZ space and then copy +the space for experiment / backup, the audio will also be copied, taking +up space. Creating a simple black-box stable media server will remove +this problem. + +Also, mirroring data between machines is easier. + +Eventually, cells to be stored as change packets in the mediaserver. + + +\subsection{Local and Cached Material} + +All material is divided into local and cached material. Cached +material may be removed from the system at any time without notice. +Removing local material requires special procedures. Material may be +changed from local to cached but not the other way around.\ajk{I'd + rather have permanent and transient material; that way someone who + absolutely wants to keep a local copy of a remote datum can do so.} + + +\subsection{Quality Levels} + +It is quite simple to expand this approach to support different +qualities for sounds and images; loading the given image at a lower +quality may be more efficient especially over a slow network, likewise +for sound. + +\section{Functionality} + +\begin{itemize} + \item communicate over network with other instances of mediaserver + \item cache media locally + \item manage local store, serve published portions over network + \item return given span of media + \item record media, tag addresses / spans + \item append text, char by char, efficiently + \item manage unique ids through prefix-for-each-server.\ajk{I have + a better idea: delegateable infinite id space. Elaborated + below.} + \item ID conflict is a fatally serious issue - exchange CRCs + occasionally for random mutually shared pieces just to check. +\end{itemize} + +\subsection{Basic interface} + +Recorder / Player? See Modules/sound/*.java + +\begin{verbatim} +interface MediaServer { + /** Load the media denoted by the span, or null if not loadable. + */ + Media getMedia(Span s); + + /** Load the media denoted by the span asynchronously + * and return + * an asynchronous object that holds the media when loaded. + */ + MediaLoader getMediaAsync(Span s); + + Span append(String s); + +} + +interface Media { + final int TEXT, IMAGE, AUDIO, VIDEO; + int getType(); + ... ??? Casts? +} + +interface MediaLoader { + /** Whether loading is complete. + */ + boolean isReady(); + + /** Whether the media has been correctly, fully loaded + * without errors. + */ + boolean isValid(); + ... ??? + + /** Stop loading. + */ + void close(); + + /** Get the final media. + * null = not yet here. + */ + Media getMedia(); +} +\end{verbatim} + +\section{Decentralized unique ID scheme proposal} + +Let IDs be octet sequences of arbitrary nonzero length. + +An ID is always either \emph{assigned} or \emph{unassigned}. + +The ID x is \emph{inferior} to ID y iff y is an initial subsequence of +x. An ID is inferior to itself. + +Let A be a mediaserver and x be an ID. Now \emph{A has delegated x} +is a relation. + +Let A be a mediaserver and x be an ID. Now define that \emph{x + available to A} iff it is not inferior to an ID that A has +delegated. + +Define the relation \emph{A has authority over x}, where A is a +mediaserver and x is an ID. + +The following invariants hold: +\begin{itemize} +\item For every ID there is a mediaserver that has authority over it. +\item If a mediaserver has authority over an unassigned ID, it can + make it an assigned ID. +\item If an ID is not available to a mediaserver, the mediaserver does + not have authority over it. +\item If a mediaserver has authority over an ID x, then it has + authority over every ID that is both inferior to the ID x and is + available to the mediaserver. +\item If a mediaserver has authority over an unassigned ID and if + there are no assigned IDs inferior to that ID, it can delegate + the ID. +\end{itemize} + +The idea is that when a mediaserver needs a fresh ID, it takes an ID +it has authority over. If it has no such IDs, it requests that some +other mediaserver delegates authority over some other ID to it. + +\subsection{Advantages} + +I believe that this scheme guarantees network-wide unique IDs. It +also requires no central agency that gives out valid IDs. + +\subsection{Vulnerabilities} + +If there are two distinct networks and data is shared between the +networks, havoc occurs. The solution is to have one conceptual global +network. The network can be disconnected; if every connected +subnetwork is seeded with a distinct part of the ID space, then each +operates autonomously after seeding. + +It is possible for a malicious mediaserver to take authority over lots +of IDs. However, this will not have any fatal effects on the +mediaserver network. + +A hostile mediaserver may also distribute invalid ids around that it has +no authority over. This is probably the most serious attack. + +\subsection{Crypto?} + +It would be good to involve cryptographic signatures here so that +assigning and delegating IDs requires a verifiable digital signature +somehow. Needs work. + +\subsubsection{A scheme} + +One possible - probably incomplete - scheme follows: + +Every mediaserver shall have an asymmetric key pair for cryptographic +signing. Additionally, there shall be a key pair for the network +distinct from the mediaserver keys. Now, a mediaserver having +authority over an ID shall possess an authority certificate for that +ID (or to an ID that ID is inferior to). + +When a mediaserver having authority over an ID wants to assign that ID +to a datum, it generates a data packet containing both the datum and +the authority certificate it has and signs that packet. + +When a mediaserver having authority over an ID wants to delegate that +ID to another mediaserver, it generates a new certificate as follows: +it generates a data packet containing the authority certificate of the +delegator the ID being delegated and information that uniquely +specifies the delegatee's public key (key ID, key size and fingerprint +or something like that), and then signs that packet. This signed +packet is the new certificate. The delegatee shall then broadcast the +certificate to the whole network. + +(An attack deflector:) If a mediaserver has a valid authority +certificate for an ID and it receives a conflicting valid authority +certificate, then there is a rogue mediaserver that is delegating the +same ID to several mediaserver. The identity of the rogue should be +easy to determine and sanctions (such as removing from the network) +doable. + +A valid certificate is defined recursively: a certificate signed by +the network key is valid, and a certificate containing a valid +certificate for the correct ID is valid. + +This scheme has at least the vulnerability that a rogue mediaserver +that is in a good place in a network can prevent the network from +realizing it's giving out conflicting certificates. + +\subsubsection{Another scheme} + +\begin{itemize} +\item There will be two kinds of authority certificates: root + certificate and delegation certificate. +\item Authority certificates are a shared secret between its issuer + and its holder. +\item An authority certificate gives its holder authority over one ID + (transitively giving authority over the whole subtree). +\item The root certificate gives authority over the null ID. (Change + above description to allow it.) +\item A mediaserver holding an authority certificate for a subtree can + generate a new authority certificate for a member of the subtree. +\item A holder of a certificate must be able to verify that the + certificate has an authority path to the root. +\item It must not be possible to generate an authority certificate +\end{itemize} + +This scheme has one problem: it does not revoke authority over a +delegated subtree from the delegator. + +\section{Architecture} + +The mediaserver proposed architecture has several levels. + +\subsection{Physical} + +The physical level takes care of retrieving and storing +spans according to unique global ids. +All policy decisions are made on higher levels: this level +only opens network connections and stores the spans in files +and removes them according to instructions from the higher level. + +No reference counting is done: that is also a problem of the higher +levels. + +\begin{verbatim} +FOO +\end{verbatim} + +\section{Implementation plan} + +\subsection{Phase I} + +This is immediate: we need this yesterday. + +Unique IDs, at least a preliminary version that will remain unique +even when better schemes taken into use. + +The physical layer, except for: +Explicit synch by user. No interactive network fetches but +code to synch up two repositories completely (copy everything +in both to both). +No digital signatures or crypto: all systems completely trusted. + + +\subsection{Phase II} + +Collections? Overriding? Signatures? + +\section{HTTP Interface to Storage} + +The storage module will listen on an IP-reachable host on an TCP port +for incoming connections. The protocol used will be HTTP/1.0 or +HTTP/1.1. It is recommended that the storage module root URL be +http://localhost/mediaserver/. The root URL shall be configurable. + +The storage module uses the following ID format: first, an arbitrary +octet sequence is encoded as a sequence of hexadecimal ASCII digits +(with capital letters); then an ASCII dash is appended; finally, an +MD5-hash of the octet sequence formed by concatenating the the +arbitrary octet sequence above and the datum itself is appended as a +sequence of hexadecimal ASCII digits (with capital letters). + +The following requests are supported: + +\subsection{Request: GET \emph{root}/data} + +A GET request of the base URL with the string \verb+data+ prepended +will result in a listing of data in the storage module. Each line +describes one datum; first comes the ID and then the +length of the datum in base-10 ASCII representation. These two fields +are separated by linear whitespace. + +\subsection{Request: GET \emph{root}/data/} + +This will result in a human-readable version of the above listing. + +\subsection{Request: GET \emph{root}/data/\emph{key}} + +A GET request of the base URL with the string \verb+data/+ and the +datum ID prepended will result in the datum requested. + +\subsection{Request: PUT \emph{root}/data/\emph{key}} + +Mutatis mutandis. + +\subsection{Request: DELETE \emph{root}/data/\emph{key}} + +Mutatis mutandis. + +\section{Problems} + +Word-sized gaps in published documents for deleted words \ra\ guess +confidential content, or damaging erased content? + +\end{document} + + + diff --git a/Documentation/Networking/Makefile b/Documentation/Networking/Makefile new file mode 100644 index 0000000..ca93a8a --- /dev/null +++ b/Documentation/Networking/Makefile @@ -0,0 +1,10 @@ +# DIAGRAMS=linkorder.png beamorder.png + +all : ztp.html ztp-ns4.html + +ztp.html : ztp.wml +ztp-ns4.html : ztp.wml + +include ../lib.mk + + diff --git a/Documentation/Networking/ZTP-usage.txt b/Documentation/Networking/ZTP-usage.txt new file mode 100644 index 0000000..cff88be --- /dev/null +++ b/Documentation/Networking/ZTP-usage.txt @@ -0,0 +1,70 @@ +Brief usage instructions for the current ZTP implementation +----------------------------------------------------------- + +You need the "ztp" module for both server and client operation. + +If your system has a BSD-style syslog service, compile with ARCH=syslog. +The Makefile is set up to work with Debian-packaged Kaffe, so if you +use some other JRE, you need to edit Java/arch/syslog/arch.mk. + + +The server +---------- + +To start up the server: + LD_LIBRARY_PATH=arch/syslog kaffe org.gzigzag.Main -ztpserv 5555 cellscrollfile1 +Here 5555 is the port to bind to. + +The only way to stop the server currently is killing it (Ctrl-C or +SIGTERM signal). + +The server does not set up the GZZ-client's system list, so if you +want to view the space generated by the server, you will have to -new +it. The ZTP cells are on the rank along d.ztpserver starting from the +home cell. ZTP dimensions and cells have a prefix "ztpserver!". + + +The client +---------- + +Create a cell with the content "ZTPclient.PUT". This will be the +action to invoke when you want to put data into the server. + +Create an association list as follows: + + ---> d.1 + | serverFQDN --- server.example (server machine FQDN) + v | + d.2 serverPort --- 5555 (server port) + | + userName --- adm (username; currently only adm works) + | + subspaceName --- ALL (only ALL currently) + | + subspace ---- (a cell) + +Connect the subspace you want to put to the "subspace" cell along +"d.ztp-subspace". The subspace is currently defined to be the closure +of the cell connected to the "subspace" cell along "d.ztp-subspace" in +positive direction with respect to all available dimensions (from +d.masterdim) except "d.ztp-subspace" and "d.cellcreation". + +Before you can do anything, you need to give your space an ID. Create +a cell with the content "SETSPACEID" and another cell with the space +ID you want as the content. Have your control cursor on the +SETSPACEID cell and your data cursor on the space ID cell. Then +invoke the action (press ENTER). + +Note that the space ID should be unique among all spaces. + +To put the subspace to the server, have your control cursor on the +"STPclient.PUT" action cell mentioned above and your data cursor on +the first item of the alist ("serverFQDN"). Then invoke the action +(press ENTER). + +To get a subspace from the server, have your control cursor on a cell +that reads "STPclient.GET" (create one if necessary) and your data +cursor on the first item of the alist ("serverFQDN"). Then invoke the +action (press ENTER). + + diff --git a/Documentation/Networking/ZTP.txt b/Documentation/Networking/ZTP.txt new file mode 100644 index 0000000..b67f4b0 --- /dev/null +++ b/Documentation/Networking/ZTP.txt @@ -0,0 +1,161 @@ +ZigZag Transport Protocol +========================= + +Objective: to transfer ZZ subspaces over a network. + +This is a datagram-oriented protocol that can operate over both TCP +and UDP. The protocol can also operate over a TLS stream. The +underlying protocol is assumed to provide for transport-level +security. + + +Authentication +-------------- + +Scenarios + + 1. Preauthentication + Used with TLS streams. + + 2. Plaintext passwords + + 3. Cryptographic authentication + +What needs to be proven? + - identity + +For now, we provide only preauthenticated and password-protected +services. + +Authority of the client to order the server to do certain things +depends on the authenticated client identity. + +Privileges: + * operator privilege + * write privilege + * read privilege + + +Naming subspaces +---------------- + +Temporary naming: + + -> Client provides server with a definition of a subspace + <- Server responds with a name for that subspace + + Client may not assume that the name is valid after this session. + + This exchange may not fail for any reason. + +Permanent naming + + -> Client provides a server with a name and a definition of + a subspace + + If successful, the name will be valid until deleted, even across + sessions. + + Names are arranged into a hierarchy. Operators of the subspace the + name refers to are operators of that name. + + NOTE: This operation requires operator privilege on the parent name. + + +Reading a subspace +------------------ + + -> Client requests a reading of a named subspace + <- Server sends a description of the subspace + + NOTE: This operation requires read privileges on that subspace + + +Writing a subspace +------------------ + + -> Client requests a writing of a named subspace + <- Server gives client goahead + -> Client sends a description of the subspace + + NOTE: This operation requires read privileges on that subspace + + +User administration +------------------- + +Admin stuff: +* Create a user +* Grant privileges to user +* Suspend a user +* Delete a user + +User stuff: +* Password change + + +PROTOCOL SPECIFICATION +====================== + +Messages: + +from client: + PASSAUTH + + TMPNAME + + PERMNAME + SUBSPACE (see TMPNAME) + + READ + + WRITE + + NEWUSER + DELUSER + + GRANTPRIV + REVOKEPRIV + + FREEZEUSER + THAWUSER + + CHPASS + + QUIT + +sequences: + SEQ CELL + SEQ HARDDIM + SEQ SOFTDIM + SEQ CONTENT + SEQ CONNECT + SEQ END + +UDP SEQ responses: + REQ SEQ + ACK SEQ END + SEQ FINISH + ACK SEQ FINISH + +non-SEQ responses: + OK + ERR + +Operation over TCP or TLS: + - all messages are sent ONCE + - SEQ messages lack seqno and num, SEQ requests lack seqno + - no acknowledgement + - each non-SEQ message is responded with OK or ERR + - OK and ERR are not responded to + +Operation over UDP: + - all non-SEQ messages are resent periodically until acknowledged + with OK or ERR + - OK and ERR are not acknowledged + - SEQ END is resent periodically until acknowledged with ACK SEQ END + - after SEQ END, SEQ receiver may send REQ SEQ requests periodically + until it receives a corresponding SEQ message, sent once. + - after ACK SEQ END and any REQ SEQ, the SEQ session is ended by SEQ FINISH + sent by receiving side until it receives ACK SEQ FINISH message + diff --git a/Documentation/Networking/mock-ZTPTCP.txt b/Documentation/Networking/mock-ZTPTCP.txt new file mode 100644 index 0000000..0a5d5e2 --- /dev/null +++ b/Documentation/Networking/mock-ZTPTCP.txt @@ -0,0 +1,74 @@ +Generic command syntax: + + command = ASCII word, args, crlf; + ASCII word = ASCII letter, ASCII word; + letter = 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 | 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; + whitespace = | 9 | 32; + crlf = 13, 10; + args = | whitespace, arg, args; + arg = ASCII word | ASCII number | UNICODE string; + ASCII number = 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57; + UNICODE string = 34, UNICODE string without quotes, 34; + UNICODE string without quotes = | quoted UNICODE char | UNICODE string without quotes; + quoted UNICODE char = UNICODE char (not 34) | 34, 34; + +Response code theory: + + X.Y.Z: + X denotes success / failure: + 1: Positive Preliminary response + 2: Positive Completion response + 3: Positive Intermediate response + 4: Transient Negative Completion response + 5: Permanent Negative Completion response + + Y denotes response class: + 0: Syntax + 1: Information + 2: Connections + 3: Authentication + 4: Subspaces + + Z with X and Y specifies exact problem + +Initial greeting: + 2.2.0 Hello there! + +Generic responses: + 5.0.1 What? (Syntax error) + 4.2.1 Service unavailable, closing transmission channel + + +QUIT + +Responses: + 2.2.1 Bye + +AUTH/PRE & AUTH/PASS + +Responses + 5.3.0 Access denied + 5.3.1 User disabled + 2.3.0 OK + +PUT + 2.4.0 Subspace successfully put + 3.4.0 Pleace proceed with subspace data + 5.4.0 Aborted PUT + 5.4.1 No such subspace + 5.4.2 Cannot put cells lacking a space ID + +GET + 2.4.1 Subspace successfully got + 3.4.1 Proceeding with subspace data + 5.4.1 No such subspace + +Subspace data: + C -- content + R ... -- rank + F -- finish \ No newline at end of file diff --git a/Documentation/Networking/ztp.wml b/Documentation/Networking/ztp.wml new file mode 100644 index 0000000..94fdaaa --- /dev/null +++ b/Documentation/Networking/ztp.wml @@ -0,0 +1,855 @@ +######### +## TODO +# * scrolls +# * +######### + + +#use wml::std::grid + +%body +%body + + + + + + + + GZigZag networking: ZigZag Transfer Protocol + +#include '../wmlinc/catart.wml' + +

GZigZag networking: ZigZag Transfer Protocol

+
$Id: ztp.wml,v 1.3 2001/02/06 12:12:17 ajk Exp $
+ +Written by
+Antti-Juhani Kaijanaho
+(add your name here if you do any significant modification) + +

+{#MYTOC#} + +On naming + +

The name of this protocol is the ZigZag Transfer Protocol, or ZTP, +as suggested by Tuomas Lukka. Early versions of this protocol were +called the Subspace Transfer Protocol, or STP, which we did not like. + +

Note that the acronym ZTP stands also for Zangelding Transfer +Protocol. Due to the different usages for the two protocols, we don't +expect that serious confusion will result from this. + +On subspaces + +

A subspace S' of a ZigZag space S is a ZigZag space with the +following properties: + +

    +
  1. The set of cells in S' is a subset of the set of cells in S +
  2. The set of connections in S' is a subset of the set of connection in S +
+ +

A subspace selector is a function mapping ZigZag spaces into their +subspaces. A subspace selector can be described by the triplet +<C, H, S>, where + +

+ +
C
+
is a set of cells,
+ +
H
+
is a set of dimensions, and
+ +
S
+
is a set of dimensions
+ +
+ +

and where H and S are disjoint. + +

Given a ZigZag space Z, a subspace selector chooses a subspace as +follows: the set of cells is constructed as the set of cells reachable +from the cells in C through connections along dimensions in H; and the +set of connections is constructed as the set of those connections from +Z whose both ends are in the subspace and whose dimension is in H or S. + +User access privilege management + +

Once the user is authenticated, her actions are limited by her +access privileges. There are four types of privileges: + +

    +
  • space administrator privileges (SAP) +
  • subspace operator privileges (SOP) +
  • subspace write privileges (SWP) +
  • subspace read privileges (SRP) +
+ +

+All but SAP are associated with a subspace. The subspace privileges +apply to the subspace itself and any subspaces of that subspace. + +

If a user has SOP, SWP or SRP in a subspace S and the same +privileges in a subspace T of S, and the privileges to T are revoked, +the privilege to S is unaffected by the revocation. + +Space Administrator Privileges (SAP) + +

A user having SAP is authorized to create, delete, suspend and +resume users, and give and revoke users their SOP to any subspace, and +give and revoke users their SAP. A user having SAP is also authorized +to revoke any user's SOP, SWP or SRP to any subspace. + +Subspace Operator Privileges (SOP) + +

A user having SOP on a subspace S is authorized to give or revoke +any user their SOP, SWP or SRP to any subspace of S, including S +itself. + +Subspace Write Privileges (SWP) + +

A user having SWP on a subspace S is authorized to initiate +transfer of any subspace of S, inclusing S itself, from the client to +the server. + +Subspace Read Privileges (SRP) + +

A user having SRP on a subspace S is authorized to initiate +transfer of any subspace of S, including S itself, from the server to +the client. + +Protocol overview + +

+ZTP is actually two similar protocols for the same purpose. One +operates over a reliable stream; we call this ZTP/TCP. The other +operates over a datagram service; we call this ZTP/UDP. Note that +other underlying protocols than TCP or UDP are possible; the names are +chosen for their mnemonic value, not for their accuracy. + +

+The datagram service used by ZTP/UDP is assumed to fail only in that +sent datagrams may be lost en route and that datagrams may arrive out +of order, and datagrams may be duplicated. In particular, it is +assumed that any arriving datagrams are uncorrupted. + +

+All transfer protocols used by ZTP/TCP and ZTP/UDP are assumed to +provide for confidentiality and integrity. However, the transfer +protocols are not necessarily assumed to provide for authentication. + +

Thus, good transfer protocols to use with ZTP/TCP are +

    +
  • TLS over TCP over IP +
  • SSL over TCP over IP +
  • TCP over IPSec +
  • SSH protocol +
+ +

UDP over IPSec is a good protocol to use with ZTP/UDP. + +

In a trusted environment, also TCP over IP with ZTP/TCP and UDP +over IP in ZTP/TCP can be used. Hovewer, using ZTP/TCP over +TCP over plain IP and using ZTP/UDP over UDP over plain IP on the +global Internet is DANGEROUS. + +

The ZTP protocol consists of several modules. The modules are: +

    +
  • authentication +
  • user administration +
  • subspace administration +
  • subspace naming +
  • subspace transfer +
  • SEQ scheme +
+ +

The authentication module actually consists of several alternative +modules. Pre-authentication is used when ZTP operates over +authenticating underlying protocols. It is also useful for +anonymous-access-only read-only servers, where there is no need for +real authentication. Password authentication is used when +the underlying protocol provides for data integrity and +confidentiality but not authentication, and in trusted unencrypted +environments. Cryptographic authentication will use +cryptographic means to authenticate the user and is meant to be used +in hostile environments. This specification will not define any +cryptographic authentication methods. + +

User administration module handles such things as adding, deleting, +suspending and resuming users. It is all things that require SAP. + +

Subspace administration module allows a user having SOP to a +subspace S give and revoke SOP, SWP and SRP to any subspace of S, +including S itself. + +

Subspace naming module uses the SEQ scheme to define a subspace and +then gives a name for it. All other subspace operations use that +name. + +

Subspace tranfer module uses the SEQ scheme to transfer a subspace +from the client to the server (which requires SWP) and from the server +to the client (which requires SRP). + +

The SEQ scheme is a method for dumping a subspace content from the +sender (either the client or the server) to the receiver (either the +client or the server, the one which is not the sender). The scheme is +simple in ZTP/TCP. In ZTP/UDP, the scheme is optimized for +transmission paths with low packet loss, allowing for information to +be used as the packets arrive, even if they come out of order. + +Protocol walkthrough + +

An ZTP protocol instance starts by establishing a session. In +ZTP/TCP, this is handled by the underlying protocol, so in ZTP/TCP +this phase consists of no messages. In ZTP/UDP, a session is +identified by an octet negotiated by the parties in a handshake +roundtrip. + +

After session has been established, user authentication is +performed. This is initiated by the client who sends a request for +authentication specifying which authentication method is desired. The +rest of the exchange depends on the authentication method; the +authentication phase is ended by an okaying or rejecting message from +the server. + +

After successful authentication, the client in the session is +assumed to be controlled by the authenticated user. It can then +initiate any process for which the user has sufficient privileges. + +

XXX Use cases + +

Connection can be closed at any time. It is preferred that the +connection closure scheme is used. The closure can be initiated by +either party at any time. In case connection is not properly closed, +a connection shall have a timeout of at least ten minutes for forcibly +closing the connection if no messages are exchanged in that time. + +Authentication schemes + +There are three schmes for authentication in ZTP. Preauthentication +presupposes that the underlying protocol provides authentication in +some implementation-defined manner. Password authentication uses a +trivial shared secret protocol to establish the authenticity of the +user. A slot for future amendment of the protocol is reserved; it is +expected that cryptographic authentication will be preferred over +password authentication in the future. This protocol specification +does not define any cryptographic authentication methods. + +Preauthentication + +

In preauthentication, the underlying protocol provides for enough +information to determine the authencity of the user at the client end. +The mechanism for that is beyond the scope of this specification. + +

The client requesting preauthentication shall send an AUTH REQ/PRE +message containing the user name for which authentication is desired. +If the server determines that the client is sufficiently authenticated +by the underlying protocol to be that user name, and the named user +exists and is not suspended, it shall respond with the AUTH OK +message. Otherwise it shall respond with an AUTH ERR message and +initiate connection closure. + +Password authentication + +

In password authentication the client provides the server with a +user name / password pair, which the server compares with its own +records. If the pair matches, the user is successfully authenticated. +The password is a shared secret; however, the server may use one-way +functions to store the information it needs of the password. + +

The client requesting password authentication shall send an AUTH +REQ/PASS message containing the user name for which authentication is +desired and the related password. If the password is determined to be +the same as the password for the user name stored in the server's +records, and the user is not suspended, the server shall respond with +the AUTH OK message. If there is no such user name, or the password +does not match, or the user is suspended, the server MUST respond with +an AUTH ERR message and initiate connection closure. + +AUTH message details + +Responses to AUTH REQ messages + +

The server MUST respond to an AUTH REQ message +with either the message AUTH OK or the message +AUTH ERR, based on the following rules: + +

    + +
  • If the server does not support the requested authentication type +at all, it MUST respond with AUTH ERR. + +
  • If the username is the name of an nonexistent user, +or it is an existing user who is not properly authenticated, the +server MUST respond with AUTH ERR. The message +sent MUST be identical between the different reasons in this item for +issuing the message. In other words, it MUST NOT be possible for the +client to determine based on the form of the message whether the user +name exists or not. An example of a proper explanation text for the +message is "Access denied". + +
  • If the username is properly authenticated and the +named user is disabled, the server MUST respond with AUTH +ERR. An example of a proper explanation text for the +message is "User disabled". Note that this kind of a message MUST NOT +be sent if the user is not properly authenticated. + +
  • If the username exists and is properly authenticated +and it is not disabled, the server SHOULD respond with AUTH +OK. However, the server MAY also respond with AUTH +ERR (for example, if there are local limits on the number of +simultaneous users and the limit is exceeded), in which case the +explanation text for the message SHOULD make it clear why the +authentication was rejected. + +
+ + +AUTH REQ/PRE + +Synopsis + +

+AUTH REQ/PRE username +

+ +
    +
  • username : string +
+ +Description + +

This message MUST be sent immediately after the connection has been +established by a client wishing for preauthentication. The +username is the name of the user for which the +authentication is requested. + +

The server responses to this message are defined in + +AUTH REQ/PASS + +Synopsis + +

AUTH REQ/PASS username password

+ +
    +
  • username, password : string +
+ +Description + +

This message MUST be sent immediately after the connection has been +established by a client wishing for password authentication. The +username is the name of the user for which the +authentication is requested. + +

The server verifies the authenticity of the user by verifying that +the password is the same as the valid password for the +username according to the server's records. Note that +the server MAY store only the result of a one-way hashing of the +password instead of the password itself, if this information can be +used to reliably ascertain the validity of a given +password. + +

The server responses to this message are defined in + +AUTH OK + +Synopsis + +

AUTH OK

+ +Description + +

This message indicates that the server has accepted the +authenticity of the client as the username given in the earlier +AUTH REQ message. This message concludes the +authentication phase. + +AUTH ERR + +Synopsis + +

AUTH ERR explanation

+ +
    + +
  • explanation : string + +
+ +Description + +

This message indicates that the server has not accepted the +authenticity of the client as the username given in the earlier +AUTH REQ message. The server, after sending this +message, SHOULD immediately initiate connection closure. + +

The explanation SHOULD be a human-readable description +of the reason for the authenticity rejection. Note that the server +SHOULD word the explanation so that the client cannot determine +whether it was failed authentication or a nonexistent username that +prompted the AUTH ERR message. + +User administration + +

The purpose of the user administration module in ZTP is to allow the +administrator to administrate users remotely without needing to resort +to implementation-defined behaviour. + +

Users have the following characteristics tunable using ZTP: + +

    +
  • User name (UNAME : string) +
  • Permission to be preauthenticated (AUTH/PRE : boolean) +
  • Permission to be password-authenticated (AUTH/PASS : boolean) +
  • Is suspended or not (SUSP : boolean) +
  • Permission to change password (CHPASS: boolean) +
  • Password (PASS : string) +
  • Has SAP or doesn't have SAP (SAP : boolean) +
+ +

The user administration module consists of one scheme for editing +and one scheme for viewing all these user data. The edition scheme +can be also used for adding and deleting new users. + +

A user can view their own data regardless of permissions. The user +can change the password if their CHPASS flag is set to +true. + +The server side user management concept + +

This section defines a conceptual model for the server side user +management for ZTP. Server implementations MAY use other +implementation strategies so long as the effects observable by the +clients are the same as with this model. + +

In the server, there is a table of users. The table consists of +records containing the following information: + +

    +
  • username : string +
  • password : string +
  • status : userstatus +
+ +

A particular record may be written as a triplet +<username, password, +status>. + +

The third element, status is an octet-length bit +vector with the following structure: + + +Bit 7 +Bit 6 +Bit 5 +Bit 4 +Bit 3 +Bit 2 +Bit 1 +Bit 0 + +Reserved +Reserved +Reserved +AUTH/PASS +AUTH/PRE +SAP +CHPASS +SUSP + + +

This data type is referred to in type definitions as +userstatus. Note that the elements marked as +Reserved MUST have the value false. + +

The table of users is indexed by user names. There may be at most +one record with a given username in the table. + +

In the table, the following operations are allowed: + +

    + +
  • insertion of a new user record; + +
  • replacement of a user record; + +
  • deletion of a user record; and + +
  • accessing a complete user record. + +
+ +

All of them are atomic. This means that, for the forementioned +operations, the following are true: + +

    + +
  • If an operation fails, the table will remain in the state it was +before the attempt. + +
  • Operations never overlap; thus at most one operation is in +progress at any time. + +
+ +

A user exists, if and only if there is a record with that username +on the table. A user is disabled if and only if there is a record +with that username on the table and the SUSP element of +the status element of that record has the value +true. A user has SAP if and only if there is a +record with that username on the table and the SAP +element of the status element of that record has the +value true + +UADM message details + +UADM NEW + +Synopsis + +

UADM NEW stat uname passwd +

+ +
    +
  • stat : userstatus +
  • uname, passwd : string +
+ +Description + +

This message is sent by the client when it wants to create a new +user.

+ +

After receiving this message, the server MUST follow the following +step-by-step algorithm (the term "client user" refers to the user +authenticated to control the session where the message was sent): + +

    + +
  • Check whether the client user has SAP. If not, the server MUST +send in response the UADM E/NOPERM message, and end +the processing of the message here. + +
  • Check whether the user uname exists. If it does, the +server MUST send in response the UADM E/EXISTS +message and end the processing of the message here. + +
  • The server SHOULD check that it has enough resources to handle +this new user (the criteria are implementation-defined and MAY include +local considerations). If it determines that it doesn't have the +resources, the server MUST send in response the UADM +E/NORES message and end the processing of the message here. + +
  • The server MUST insert the record <uname, +passwd, stat> into the user table. If +this fails, it MUST respond with the message UADM +E/PROB, otherwise it MUST respond with the message +UADM OK. + +
+ + +Payload transfer: the SEQ scheme + +

+The actual payload of the protocol, the subspace data, is transferred +over by the SEQ scheme. + +

The SEQ scheme consists of five SEQ data messages and four SEQ +control messages. The data messages are + +

+ +
SEQ CELL
+
Specifies a root cell for a subspace
+ +
SEQ HARDDIM
+
Specifies a hard dimension for a subspace
+ +
SEQ SOFTDIM
+
Specifies a soft dimension for a subspace
+ +
SEQ CONTENT
+
Transfers over the content of a subspace
+ +
SEQ RANK
+
Specifies a subrank in the subspace
+ +
+ +

+The SEQ control messages are listed below. + +

+ +
SEQ FIN
+
Initiates finalization phase of the SEQ scheme
+ +
SEQ REQ
+
Requests that a SEQ data message is resent
+ +
SEQ ERR
+
Response for a broken SEQ REQ.
+ +
SEQ END
+
Ends the SEQ scheme instance
+ +
+ +

A SEQ scheme instance has a sending end and a receiving end. When +the server is the sending end, the client is the receiving end and +vice versa. + +

In ZTP/TCP, the SEQ scheme consists of a number of SEQ data +messages and is finished by a SEQ END message. + +

In ZTP/UDP, the SEQ scheme consists of two phases: the data +transfer phase and the finalization phase. The data transfer phase +consists of a number of SEQ data messages and is ended by a SEQ FIN +message which also starts the finalization phase. Then the receiver +end of the SEQ scheme sends one or more SEQ REQ messages and the +sender end responds with an appropriate SEQ data message. The +finalization phase is ended by a SEQ END by both parties. + +SEQ message details + +SEQ/DATA message template + +SEQ/CTL message template + +SEQ CELL + +Synopsis + +

+SEQ/DATA CELL cellid
+

    +
  • cellid : string +
+ +Description + +

This message defines that the cell cellid is a root +cell for the subspace being described. + +SEQ HARDDIM + +Synopsis + +

+SEQ/DATA HARDDIM dimid +

+ +
    +
  • dimid: string +
+ +Description + +

This message defines that the dimension dimid is one +of the defining dimensions for the subspace being described. In other +words, this defines that any cell connected to any cell in the +subspace along dimension dimid also is in the subspace. + +

If in a SEQ scheme instance a dimension is specified using +SEQ HARDDIM, it SHOULD NOT be specified in the same +SEQ scheme instance using SEQ SOFTDIM. + +SEQ SOFTDIM + +Synopsis + +

+SEQ/DATA SOFTDIM dimid +

+
    +
  • dimid: string +
+ +Description + +

This message defines that any connections along dimension +dimid between cells that are in the subspace are included +in the subspace. However, this dimension will not take part in the +definition of the cell set of the subspace. + +

If in a SEQ scheme instance a dimension is specified using +SEQ SOFTDIM, it SHOULD NOT be specified in the same +SEQ scheme instance using SEQ HARDDIM. + +SEQ CONTENT + +Synopsis + +

SEQ/DATA CONTENT +content-type cellid content +

+
    +
  • content-type: octet +
  • cellid: string +
  • content: octet[] +
+ +Description + +

This command transfers the content of a cell, which this protocol +treats as an octet stream with no underlying structure. The type of +the content is indicated in this messages; the following content types +are now established: + + + + +0 +Octet stream, ie. unknown format + +1 +Unicode text in UTF-8 encoding + +2 +A span + + + +SEQ RANK + +Synopsis + +

SEQ/DATA RANK +dimid cellarray + +

    +
  • dimid : string +
  • cellarray : string[] +
+ +Description + +

This message denotes a subrank along dimension dimid. + +

The precise definition of this is as follows: +cellarray[n] is connected posward to +cellarray[n+1] for all n +between zero, inclusive, and the length of cellarray +minus one, exclusive. More than one SEQ RANK +message MAY define the same connection. Two SEQ +RANK messages MUST NOT define two conflicting connections +(that is, a connection posward or negward from the same cell to two +different cells). + +SEQ FIN + +Synopsis + +

SEQ/CTL FIN dmcount + +

    +
  • dmcount: uint32 +
+ +Description + +

This message closes the data transfer phase of a SEQ scheme +instance and opens its finalization phase. + +

The parameter dmcount MUST specify the number of +unique SEQ data messages sent during the data transfer phase of the +SEQ scheme instance. + +

In ZTP/UDP, the sending end of the SEQ scheme instance MUST send +this message repeatedly after sending the last SEQ data message in the +data transfer phase, until it receives either a SEQ REQ or a SEQ END +message. + +

When the receiving end of the SEQ scheme instance first receives +this message, it SHOULD check which data messages it did receive and +issue SEQ REQ messages for each missing message. When it has received +all data messages, it MUST send a SEQ END message. It should ignore +all further SEQ FIN messages associated with that SEQ scheme instance. + +

This message MUST NOT be sent in ZTP/TCP. + +SEQ REQ + +Synopsis + +

+SEQ/CTL REQ seq +

+ +
    +
  • seq : uint32 +
+ +Description + +

This message is sent by the receiving end of the SEQ scheme +instance to request that the sending end resend the SEQ data message +with the SEQ message identity number seq. + +

The receiving end MUST repeatedly resend this message if it is +sending it at all, until it receives the data message it's asking for +or a corresponding SEQ ERR. + +

The sending end MUST respond to each SEQ REQ +message it receives (even duplicates) by resending the message being +requested, or with a SEQ ERR message. + +

This message MUST NOT be sent in ZTP/TCP + +SEQ ERR + +Synopsis + +

+SEQ/CTL ERR seq +

+ +
    +
  • seq : uint32 +
+ +Description + +

This message is a response to an invalid SEQ REQ +message. It is to be sent in response to every received invalid +SEQ REQ message, even to duplicates. + +

This message MUST NOT be sent in ZTP/TCP. + +SEQ END + +Synopsis + +

+SEQ/CTL END +

+ +Description + +

This message ends the SEQ scheme instance. + +

In ZTP/UDP, the receiving end MUST send this message repeatedly +after receiving SEQ FIN and receiving all the data +it needs, until it receives a SEQ END message. The +sending end MUST respond to every SEQ END message, +even duplicates, with a SEQ END message. + +

In ZTP/TCP, the sending end MUST send a single SEQ +END message after sending all the SEQ data messages it's +going to send. The receiving end MUST NOT respond to the SEQ +END message. + diff --git a/Documentation/Nile/Makefile b/Documentation/Nile/Makefile new file mode 100644 index 0000000..ea4bf90 --- /dev/null +++ b/Documentation/Nile/Makefile @@ -0,0 +1,14 @@ +# DIAGRAMS=linkorder.png beamorder.png + +all : nileug.html nileug-ns4.html nile.html nile-ns4.html + +niledep = nile.wml ../wmlinc/art.css ../wmlinc/catart.wml ../wmlinc/common.wml $(DIAGRAMS) +nileugdep = nileug.wml ../wmlinc/art.css ../wmlinc/catart.wml ../wmlinc/common.wml $(DIAGRAMS) +nile.html: $(niledep) +nile-ns4.html: $(niledep) +nileug.html: $(nileugdep) +nileug-ns4.html: $(nileugdep) + +include ../lib.mk + + diff --git a/Documentation/Nile/nile.wml b/Documentation/Nile/nile.wml new file mode 100644 index 0000000..ad6d6a9 --- /dev/null +++ b/Documentation/Nile/nile.wml @@ -0,0 +1,259 @@ + + + +#include "catart.wml" + + +The nile (nile is a literate editor) applitude +

$Id: nile.wml,v 1.4 2000/12/08 23:05:20 tjl Exp $
+ + Tuomas J. Lukka
+ lukka@iki.fi +
+
+ + + +

+This is a short, living (hopefully) description of the Nile applitude +and issues related to it. + +

+{#MYTOC#} + +Note + +

+ Writing this document is bothersome, because now that the idea + of Nile exists in my head, using conventional writing tools is + annoying, to put it mildly. I can now very easily sympathize + with the Xanadu group not publishing too much about their work - + describing a much easier system for writing using a much more + difficult system seems almost a sacrilege. + +

+ However, this must be done. If there is no conversation + and no exchange of ideas, there is nothing. + +Introduction + +

+ The idea of nile is to experiment with doing "word processing" + (for want of better term) in ZigZag. It is by no means a final + system but already the plans for it contain several features + not found in current products. + +

+ +Units + +

+ Here, we define Nile's units for the following sections. + For each unit, the unit itself and the insertion points + are described. The insertion points are simply the points + in the stream where units of this type may be inserted. + +

+ XXX Should discuss also cutting and pasting behaviour here. + + Characters + +

+ Not much to say - pretty usual stuff. + Characters may be inserted anywhere. + + Words + +

+ A word is defined either as a sequence of alphanumeric characters, + or a single punctuation character. + Words are usually separated by spaces. + +

+ This definition is not yet complete - e.g. the handling of + smileys is incorrect, but it will do for the first version. + +

+ Words may be inserted before any other word, or at the end + of a paragraph. + +

+ Cutting and pasting words is not terribly simple because + of the way people expect them to behave. + The following drafts are rudimentary and may be in need + of significant adjustment. + +

+ When words are cut away, +

+if the word is only punctuation,
+	do nothing.
+if there is a following space or two spaces,
+	cut them along
+else, if there is a preceding space,
+	delete it.
+
+ Deleting the preceding space seems an easier alternative than + having to test for it later, at paste time. + +

+ When words are pasted, +

+if there is a space or paragraph break
+   preceding the paste location
+	paste at that location and make 
+	sure the last pasted character
+	is a space (insert if necessary)
+else if there is a space after the paste location
+	SHOULD NOT HAPPEN
+else if one of the adjacent characters is alphanumeric,
+	make sure there is a space on its side.
+
+ +

+ Except that it isn't quite that easy when punctuation + is involved. This is because we need to remember where + the punctuation was but still leave a space. + If the span to be cut away starts with punctuation, cut + all spaces before it as well as after, but insert an extra + space after having cut, if there was a space + in the end of the cut-away piece. This is still + a bit under development... + +

+ Probably I should enumerate all the possible cases here... + Brackets are the part cut away, Parentheses are the + original selected part, and an asterisk means a space added + after the cut. +

+	A [(B) ]C
+	A B[(, C) ]*D
+	...
+	
+ + Sentences + +

+ A sentence is defined as a sequence of alphanumeric characters, + punctuation and spaces that does not contain a double space anywhere + inside itself and does not start or end in a space. + Sentences are usually separated by double spaces, or alternatively + paragraph edges. + +

+ The choice of the double space is meaningful, but no time to + go into that here. + +

+ Sentences may be inserted before any other sentence, or at the end + of a paragraph. + +

+ When sentences are cut, cut the spaces after the last sentence along. + When they are pasted, make sure there are two spaces or + a paragraph beginning before the start. + + + Paragraphs + +

+ The beginning of a paragraph is marked by a special (empty) cell + in the Nile stream. Another cell, connected to the cell in the + stream tells which level of paragraph it is (H1..H6 or P, as in HTML). + +

+ Paragraphs may be inserted before any paragraph or at + the end of the stream. + +

+ Cutting and pasting paragraphs is simple: + when cutting, it must be from the initial marker cell, + up to either the end of the stream or just before another marker + cell. + When pasting, it has to go just before another marker cell + or at the end of the stream, and then everything works out. + +Modes + +

+ One of the special features of nile is that it is more + explicitly aware of the nature of text than conventional + word processors. + While e.g. recent versions of MS-Word take a mouse selection + to be at word boundaries by default, Nile goes much further + and allows the user special movement modes. + +

+ One of the underlying ideas (which Ted has been talking + about for a LONG time) here is that once a text is initially + written, there is a long period of rearrangement and revision -- + often longer than the initial writing. + In that phase, the most of the editing actions are concerned with + rearranging words, phrases, sentences, paragraphs and sections. + +

+ However, most current programs, such as e.g. Mozilla's composer, + only deal with characters and force the user to exactly aim at the word + boundaries himself. Support for words and sentences is small; + double-clicking on a word selects that word but selecting two words + requires careful aim. In MS-Word, selecting two words is fairly easy + -- but selecting two sentences again requires more aiming. + +

+ Also, after selecting the part of text, we come to one of Ted's + favorite gripes: cut&paste. To move the text to another location, + it will first have to be vanished from the screen and then + vomited out at another location. + + The Nile solution + +

+ The solution used in Nile is the hop operation. + This operation, available for cells in the usual cell view + of GZigZag performs rearrangements such as + ABCDE into ABDCE. + +

+ The hops happen along the natural units: when word or several + words are selected, they hop one word at a time, when sentence(s) + are selected, they hop one sentence at a time etc. + Of course, a super-hop operation can also be useful, which would + hop words a sentence at a time etc. + +

+ One of the reasons why hop is natural is that all text is visible + at all times. This is especially true in the GZigZag implementation, + where the infrastructure provides animation between frames. + So hopping a word causes a smooth animation to happen where the + words exchange places. This visibility makes it easier + for the user to orient to the new way the text is laid out. + There is no abrupt rebreaking of lines either: the words which + jump from one line to another also smoothly glide over. + +

+ It is important that the hop operation be reversible: + hopping left and then right should ALWAYS produce the + same text as the original, unless the hop left command + bumped into the left edge of the document. + Someone should probably go over the definitions of the word + operations mathematically to think about how to ensure + that this property works always. + + + + + + + + + + diff --git a/Documentation/Nile/nileug.wml b/Documentation/Nile/nileug.wml new file mode 100644 index 0000000..c4a28c5 --- /dev/null +++ b/Documentation/Nile/nileug.wml @@ -0,0 +1,114 @@ + + + +#include "catart.wml" +#use wml::fmt::xtable + + +Nile User's Guide +

$Id: nileug.wml,v 1.1 2000/12/09 02:29:35 tjl Exp $
+ + Tuomas J. Lukka
+ lukka@iki.fi +
+
+ + + +

+A short introduction to using Nile, mostly for explaining the +keybindings. + +

+{#MYTOC#} + +Warning + +

+ This document may be out of date. If this seems to be the case, + please contact the author. + +Keystrokes + +

+ Unlike most current word processors, + Nile has several different modes. + This may seem complicated but the modes are fairly natural. + The most commonly used modes are the character, word and + sentence modes, through which the user can move with the + TAB key. In these modes, the following cursor keys apply: + + + + + (=,1) colspan=2 + Moving and hopping text + (+,1) + Left/Right + (=, 2) + Move the cursor + (+,1) + Shift-Left/Right + (=, 2) + Extend the cursor + (+,1) + Ctrl-Left/Right + (=, 2) + Shrink the cursor + (+,1) + Alt-Left/Right + (=, 2) + Hop the selected text + + + + + (=,1) colspan=2 + Deleting text + (+,1) + Backspace + (=, 2) + Delete the previous unit. + (+,1) + Delete + (=, 2) + Delete the selected text. + + + + (=,1) colspan=2 + Inserting text and changing modes + (+,1) + [text] + (=, 2) + Insert the letter and move to character mode. + + (+,1) + Enter + (=, 2) + Break the paragraph. + (+,1) + Tab + (=, 2) + Move to the next mode. + + + + + + + + + + + diff --git a/Documentation/PROTOCOL b/Documentation/PROTOCOL new file mode 100644 index 0000000..d01d110 --- /dev/null +++ b/Documentation/PROTOCOL @@ -0,0 +1,192 @@ +Version 0.03 of the *active* ZZ protocol. To be used over short +distances and reliable connections. + +Ascii pipe / file / ... + +Newlines: UNIX-style + +Initiation: + +SERV: + ZZ(protoversion)(uniqueservid)(serversessionid) +CLI: + ZZ(protoversion)(uniqueclientid)(clientsessionid) + + +Home cell is always cell id 1. id 0 does not exist. So a natural start +would be + + 1 ref(1)(+1) + +Requests always made with reqno and may be answered out of order. +Reqno is a simple integer. + + ()()... + +Reply: + (... + +E.g. + +CLI + 50 getcell(24)(d.1)(+) +SERV + 50 cellno(40) + +or if no cell is there, + 50 cellno(0) + +EXCEPTION: +for get text and set text, the last parameter is a number, then newline +and then number bytes of binary data, not followed by newline. + +The requests are + + get()()(

)()() ---> cellno + gethead()()()()() ---> cellno + sethead()()() ---> ok + new()()()()() ---> cellno + delete() ---> ok + connect()()() ---> ok + insert()()()() ---> ok + disconnect()()() ---> ok + gettext() ---> text + settext()() ---> ok + ref()() ---> ok + lock()() ---> locked + unlock()() ---> ok + execute()()()() ---> ok + clearerr(errorid) ---> ok + +And the responses: + + cellno() + locked() + wouldblock() --- if requested non-waiting lock didn't work + ok --- no parameter + text()() + error(errorid)(errorstring) + +REFERENCE COUNTING AND INFORMING: + +The client asks the server to hold in mind that the client has n references +to a cell and wishes to be informed about any changes. The parameter +of the requests if for this purpose: it contains the number of references +this client will have to the cell. When the count goes to zero, +the server need not inform the client about changes. + +The ref request can be used to create more references or unreference, +via a negative . + +The informing happens through the special reqno code -1: + + -1 changed() + +The reason for the ref parameter for all the calls that return cells +is to avoid race conditions: getting the cell first and then referring +allows the cell to be changed in between: e.g. + + A --- B + +we know cell A and get cell B through it but before we ref it, someone +severs the link: + + A B + +but since our ref request is received only after this, we never find out +about this and assume they are still connected. Therefore, to avoid +race conditions, the immediate ref:ing is possible. + +Since the client can't otherwise behave correctly, there is a special +code when the cell is deleted: + + -1 deleted() + +since otherwise the client might try to get neighbours of the deleted +cell. + +LOCKING + +The parameter represents the number of locks this process +wants on the cell - generally 1. +The lock does NOT preclude any other client from doing anything but only +stops others from locking the cell. Locks can be requested synchronously +or asynchronously, in three different ways: + + 1. lock = "1" -> tries to lock, returns wouldblock if can't + 2. lock = "1w" -> tries to lock, waits until can lock. DEADLOCK DANGER + 3. lock = "1a" -> tries to lock, sends the locked command + only once the lock is obtained - the other results of the request + will keep going. + +A server has the right not to support any locking --- it is possible +to put a protocol filter on top of it that does. + + + +ERRORS + +If it is likely that two processes would modify the same cells, they should +agree to lock the cells. In that case, the fastest processing times would +be achieved through performing all these operations in one row: + + lock(50)(1w) + new(50)... # operate + unlock(50) + +Because of this, there needs to be a way of performing a series of +operations but only if all of them are successful. Therefore, after +sending an error, the server will wait for the clearerr command and +ignore all the commands before it. Since the error has the number of the +request in front of the command, the client will be aware of what has happened. + +This way many useless context switches can be avoided. + + + +======================================= +PROPOSAL: New change op. +Idea from Benjamin Fallenstein. + +Instead of new, delete, connect, insert, disconnect, settext you would +simply have one command to upload a fragment of zzspace, possibly identified +with a current fragment. + +So + uploadfrag + curcell(O) + delcell() + newcell(N) + connection()()()() + endupload + +where ONid is O, N or 0. + +Thus, disconnect(15, d.1, +) would be + + uploadfrag + curcell(Ocell) + connection(Ocell)(d.1)(+)(0) + endupload + +and insert(f, d.1, +, w) where the next cell after f is g, is + + uploadfrag + curcell(Of) + curcell(Og) + curcell(Ow) + connection(Of)(d.1)(+)(Ow) + connection(Ow)(d.1)(+)(Og) + endupload + +By default, all the other connections remain. + +OTOH, insert is a nice primitive operation for many things, like cursors.... +On the other hand, an operation like jump is dangerous to synchronize +otherwise, implemented using the above connect operation. + +An uploadfrag can be guaranteed to be atomic... this + locking begins +sounding good. + +- keep insert and uploadfrag, discard others? + diff --git a/Documentation/README b/Documentation/README new file mode 100644 index 0000000..3f1ad6c --- /dev/null +++ b/Documentation/README @@ -0,0 +1,55 @@ +NOTE: do contact the author (lukka@iki.fi for most of the stuff) if +there is an unfinished part that you really need - I sometimes need +prodding to get things finished. Comments are also appreciated. + +NOTE 2: +THE SUBDIRECTORIES THAT ARE CURRENTLY BEING ACTIVELY WRITTEN ARE +CyberText, DesignProblems and Spec. THE OTHERS ARE A BIT STALE. + +I recommend starting with the Gentle_Introduction and then working your +way through the others if the subject matters interests you (for example, +if you are not hacking the internals, CellScroll will not be interesting +to you). + +Some of the documents are written in LaTeX using gpic to compile +diagrams (since it seems more reasonable than e.g. xypic or any +picture language I've seen for LaTeX). See the Makefile for how +the process is supposed to go. The LaTeX files also use rcs.sty, +which is available in the Debian linux package rcs-latex, but also +probably from CTAN. I'm planning to put up autogenerated PostScript +files of these Real Soon Now. + +The files in this directory: + +Gentle_Introduction/ + an introduction to what ZigZag is and how it works. + +Clang_Design/ + Clang is a language for writing programs using the ZigZag + structure... no, better to say: Clang is a way of interpreting + a certain kind of ZigZag structure as a program. + This document discusses the various issues at stake when + designing Clang. + +CellScroll/ + CellScrolls are a way to store both the current state + and all former states of a ZigZag space. + +Interfacing/ + +misc/ + odds and ends + +DimBased/ + Some thoughs on reorganization of the model to think about ZZ + in the code to be based on dimensions, not so much cells. + +PROTOCOL + ASCII description of the ZZ network protocol. Don't rely on this: + use the source, Luke. + + The protocol needs some rethinking anyway. + +wmlinc/ + Some include files used in the WML (website modeling language) + files around. diff --git a/Documentation/STARTING b/Documentation/STARTING new file mode 100644 index 0000000..f6a8417 --- /dev/null +++ b/Documentation/STARTING @@ -0,0 +1,24 @@ +$Id: STARTING,v 1.2 2000/09/09 13:37:32 tjl Exp $ + +Documenting how to start with GZigZag is difficult because it +is a moving target. So if there are any discrepancies with the +current CVS version and this document, please ask me (lukka@iki.fi) +to update it. +Especially the keystrokes are liable to change soon. This is the situation +at the date given above. + +When you first start GZigZag, you get two windows showing cells and +their connections. +The system works so that +you click on the right-hand window to focus on it and then all you need +is the keyboard: you can forget the mouse (it does work though: clicking +on a cell moves to it). + +For the cursor motion you have the keys "IJL," and "ESFC". Pressing Tab +will give you a text insertion cursor that you can move sideways with the +arrow keys. + +Other commands are n- for new cell, / (slash)- for connecting +two cells etc. They are shown in the user's guide. + +Any other questions, just mail me. diff --git a/Documentation/Slices/SliceLogic b/Documentation/Slices/SliceLogic new file mode 100644 index 0000000..bd94b9e --- /dev/null +++ b/Documentation/Slices/SliceLogic @@ -0,0 +1,179 @@ +Date: Tue, 14 Jul 1998 19:35:41 +0900 +To: zzdev@xanadu.net +From: Ted Nelson +Subject: :zz: ZigZag Design Notes: SLICE LOGIC 1 (d6 +Cc: ted + +zzSliceLogic.d6 +98.07.14 + +[illustration accompanying this email: zzSliceLogic.bmp] + +SLICE LOGIC 1 + +The main objective of the ZigZag Slice system is to be able to combine +pieces of zzstructure. Relatively fixed material (ends of rows, ends of +columns, titles) are expected to stay in RAM, with other stuff coming and +going. + +Further objectives: +- to limit RAM usage without going to some system of virtual memory +- to allow the user to select the portions being worked on +- to allow slices to slide into the middle of other slices according to the +user's desire. (Thus slices should be connectable anywhere, even in the +middle of ranks.) + +MANY logics and rule-sets are possible for this. I have thought about this +for some years. + +What follows is the simplest method I could work out that does the job +neatly. It is called "Slice Logic 1" because it's the easy one that I +think we should implement first. (Last week I produced a document with a +more complex system, possibly for implementation later, and quite +interesting technically-- I think-- but I want you to see this one first.) + +This system need not be implemented all at once. For instance, we can +forbid Part II at first. + +- - - - - +PART 0. SKIP ON FIRST READING. + +0000. (If a rank has a leading edge, it cannot be a ringrank and +necessarily has a trailing edge.) + +000. ASSUME that the user can neatly divide the world into slices. +Slices, like dimensions, may have any names, but with a prefix: slices +begin with "s.". Lexical order thereafter will be significant. + + +00. There may be a d.slice and d.slicelist, not discussed here. +(Eventually-- or now if there is a need-- the list of slices can be +maintained along d.slice, and the cells of a slice can be connected on a +list in d.slicelist. Still under consideration.) + +- - - - - +PART I. PREFLET LOGIC. + +0. A ZigZag slice is a data set with cells which may be connected to each +other in the ordinary ZZ way. But not necessarily; there may also be loose +cells in the slice. + +1. Slice 0 (s.0) is always resident. + +Other slices may be called in as needed. + +2. Slices are independent structures. CONNECTIONS BETWEEN SLICES ARE NOT +OF THE USUAL KIND, with doubly-linked cells. Instead, they have +*preferred* points of attachment. + +3. PREFERENCE OF ATTACHMENT IS EXPRESSED BY MEANS OF A 'PREFLET'-- a piece +of information in the cell specifying a cell in another slice to which it +would *like* to be attached, negward, in a specified dimension. + +In the current design, a cell may have only one preflet in a given +dimension. + +4. The process of resolving preflets determines the way in which the +slices are attached. However, once attached, the slices are stitched +together doubly-linked in RAM somehow as ordinary zzcells. (Implementation +is not significant; eventually different slices should be storable by +different databases or other methods.) + +5. When a slice is brought in, only the preflets of its leading edge-- all +the negend cells-- are considered. (This could be done thusly: test all +cells to see if they are negends; test all negends for preflets.) + +6. Any cell with a preflet for a cell already resident, and not contested +by any other cell's preflet, gets to insert/attach itself to the specified +cell. + +7. If a cell has a preflet for a cell which is not currently resident, the +preflet is ignored. + +8. Two cells may have to be separated to honor a preflet specifying one of +them. These two cells will rejoin when the slice is swapped out, if +appropriate. + +IF THEY HAVE A LOCKED LINK (not yet implemented), they may not be separated. + +9. If two leading cells in two slices both have a preflet for the same +cell in another slice which is resident, the slice with lower lexical order +wins-- and the second slice attaches itself *indirectly*, to the trailing +edge (posend) of the winning cell's rank. See illustration. + +10. If two leading cells in the same slice A have a preflet for the same +cell in a second slice B which is resident, the slice with lexically lower +cellname wins-- and the second slice attaches itself *indirectly*, to the +trailing edge (posend) of the winning cell's rank. See illustration. +(This would probably lead to the two ranks in A later becoming a single +rank, due to rule 12.) + +11. Whenever a slice is swapped in or out, the preflets of all current +slices must be resolved again. + +12. Whenever a slice is swapped out, its detached negends are given +preflets again. These preflets will normally be to the cells from which +the cell has just been detached in s.0-- either directly or indirectly. + +13. If swapping a slice out severs a rank in some other slice (usually +s.0), that rank is reconnected where the swapped-out cells have just been +taken away. (This will re-attach cells which were separated by the +incoming slice, unless they have been moved.) + +- - - - - +EXAMPLE. + +Consider the illustration. Assume that the x-axis is d.1 and the y-axis is +d.2. + +Not shown is s.0, which contains cells 16, 42, 131, 265 and 22. These are +not necessarily negends. + +Shown are two slices, s.2 and s.4. They have leading-edge preflets for +some of the same cells in s.0. + +The preflets for 13 and 22 take effect without conflict. What follows is +about resolving the others. + +Both s.2 and s.4 have a leading-edge preflet in d.2 for cell 16. s.0 wins. + The cell in s.4 with a preflet for 16 connects to the *trailing* edge of +the same rank in s.2 (cell 68). + +Similarly, both slices share a preflet for cell 42 in d.2. s.2 wins, and +s.4 connects to the trailing cell in the same rank, cell 4. + +Similarly, both slices share a preflet for cell 265 in d.1. s.2 wins, and +s.4 connects to the trailing cell in the same rank, cell 31. + +If s.2 is swapped out, preflets are considered again at the leading edges +of all slices (except s.0). Thus s.4's preflets for 16, 42 and 265 then +cause them to be directly attached to 16, 42 and 265. + +If s.4 is then swapped out, each rank of s.4 which is extracted from within +a rank in s.0 causes that rank in s.0 to be reconnected. + +- - - - - +PART TWO: CROSSING OF CELLS BETWEEN SLICES. (May be disallowed in Phase 1.) + +13. (The user somehow knows where the slice boundaries are.) + +14. If a cell is moved / hopped / connected into a different slice, and +has *no* other connections to its former slice, all its contents are moved. + The information that travels with it includes its contents, processor of +origin, cell of origin, and which slice the cell of origin is on. + +15. If a cell is moved / hopped / connected / cloned into a different +slice, and retains connections to its former slice, a Remote Clone is +made. The information that travels with it includes its contents, +processor of origin, cell of origin, and which slice the cell of origin is on. + +16. When a cell is swapped in, Remote Clones must be resolved. + +If a Remote Clone's connections in all slices are consistent with each +other, it is considered to be one with its origin, and they are shown as +only one cell. However, if they are inconsistent-- more than one +connection posward or negative in a given dimension-- the second instance +is deemed to be a clone. After each operation its connections should be +checked for compressibility to one cell. + + diff --git a/Documentation/Slices/zzSliceLogic.jpg b/Documentation/Slices/zzSliceLogic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b090963c8f8708a331b9e592aca65b3b5717c6e GIT binary patch literal 81225 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 literal 0 HcmV?d00001 diff --git a/Documentation/Spec/Makefile b/Documentation/Spec/Makefile new file mode 100644 index 0000000..5a8bd26 --- /dev/null +++ b/Documentation/Spec/Makefile @@ -0,0 +1,15 @@ +# DIAGRAMS=linkorder.png beamorder.png +DIAGRAMS=cursor1.png cursordim.png canvasraster.png rasterspec.png \ + inheritparam.png +DEP=../wmlinc/article.wml + +all : zzspec.html zzspec-ns4.html + +zzspec.html: zzspec.wml ../keybindings.wml $(DIAGRAMS) $(DEP) + +zzspec-ns4.html: zzspec.wml ../keybindings.wml $(DIAGRAMS) $(DEP) + +include ../lib.mk + + + diff --git a/Documentation/Spec/canvasraster.dia b/Documentation/Spec/canvasraster.dia new file mode 100644 index 0000000..27d98aa --- /dev/null +++ b/Documentation/Spec/canvasraster.dia @@ -0,0 +1,427 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #viewspx# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #CanvasRaster# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.cursor-cargo +and +d.cursor# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #R# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.2# + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/Spec/cursor1.dia b/Documentation/Spec/cursor1.dia new file mode 100644 index 0000000..13bcb85 --- /dev/null +++ b/Documentation/Spec/cursor1.dia @@ -0,0 +1,590 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #viewspx# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #A# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #C# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.cursor# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.cursor-cargo# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #...# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #...# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/Spec/cursordim.dia b/Documentation/Spec/cursordim.dia new file mode 100644 index 0000000..d27b430 --- /dev/null +++ b/Documentation/Spec/cursordim.dia @@ -0,0 +1,769 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Y# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #A# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #C# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.cursor# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.cursor-cargo# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #...# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #...# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #viewspx# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #X# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.dims# + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/Spec/email1.dia b/Documentation/Spec/email1.dia new file mode 100644 index 0000000..a76e848 --- /dev/null +++ b/Documentation/Spec/email1.dia @@ -0,0 +1,597 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Mailboxes, other structure# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.ref# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.handle# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/Spec/inheritparam.dia b/Documentation/Spec/inheritparam.dia new file mode 100644 index 0000000..3a072ce --- /dev/null +++ b/Documentation/Spec/inheritparam.dia @@ -0,0 +1,885 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #start# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #param# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #value# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #+# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #param# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #param# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #value# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #Traversal# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.1# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.2# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.3# + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/Spec/rasterspec.dia b/Documentation/Spec/rasterspec.dia new file mode 100644 index 0000000..322c8ae --- /dev/null +++ b/Documentation/Spec/rasterspec.dia @@ -0,0 +1,678 @@ + + + + + + + + + + #A4# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #vanishing# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #gap# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #5# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #5# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #depth# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #6# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.2# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #d.1# + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/Spec/zzspec.wml b/Documentation/Spec/zzspec.wml new file mode 100644 index 0000000..f67a882 --- /dev/null +++ b/Documentation/Spec/zzspec.wml @@ -0,0 +1,1127 @@ + + + + + + GZigZag spec + +#include '../wmlinc/article.wml' +#use wml::fmt::xtable + + + + + + +

GZigZag spec

+
$Id: zzspec.wml,v 1.24 2001/02/13 18:54:28 ajk Exp $
+ +Written by
+Tuomas J. Lukka
+Benjamin Fallenstein
+Antti-Juhani Kaijanaho
+(add your name here if you do any significant modification) + + + + + +

Introduction

+ +

+The purpose of this document is to be a living specification of the +features in the GZigZag system. The GZigZag system is an implementation +of the ZigZag structure, invented by Ted Nelson. Much of this document +is simply a somewhat more verbose version of discussions with him but +other places go into more technical detail. + +

+Some parts of this specification are not yet correctly implemented by +the current version, but in these cases, this document is correct (or +it should be ;-) +and the implementation wrong. + +

+Some parts of this spec are at the moment +just general ramblings about a topic - once +we have the pole editor, I will definitely rearrange it completely. +The idea is to try to make them more and more like a true spec as +time goes by. + +

+The parts marked with the dreaded triple-X symbol (XXX) are as yet incomplete +and should be taken with a not only a grain but a mountain of salt. They +mostly contain just a few loose sentences setting the topic. + +

+If you see anything suspicious, feel free to ask me at lukka@iki.fi. + + + +

The role of ZigZag in the overall scheme of things

+ +

+ZigZag is a delightfully simple way of operating structures. +As such, it has its own uses simply as a personal information manager +for people who like multidimensionality, + +

+In addition to stand-alone use +ZigZag is related to Ted Nelson's Xanadu system; a newer version of Xanadu +is being designed to make use of ZigZag as a platform. +As a brief description of Xanadu, it has +

+
Stable media streams (permascrolls) +
A stable media stream is an invariant, addressable stream of + data, e.g.~text, video or audio. +
Documents +
In Xanadu, documents + are simply lists of spans from the stable + media streams. +
Content links +
The linking model is fundamentally different + from anything else hitherto seen. All links are handled on the + lowest level, i.e. as links between lists of spans of stable + media streams. +
Finding by content +
There are fast ways to find out in which + documents a particular point in a stable media stream is + included. All content copied via cut&paste can be tracked. +
+ +

+ZigZag can also work as a platform for other types of applications +--- or preferably applitudes, meaning that they should also expose the +other possibilities of ZigZag at the same time as being normal +applications. This is so that the interconnectivity provided by ZigZag +can be used to make the whole of two applitudes greater than the sum +of the parts. + + +

Cells, dimensions and connections

+ +

A cell is the fundamental container of data. A cell can +"physically" contain either a text string or a single, contiguous span +(which is an address, and references a permascroll). + +

A cell has an ID, which is a string. Currently, if a cell ID +contains a colon (:), the cell belongs to a space part, where +the space part ID is everything from the beginning up to and excluding +the colon. If a cell ID contains an at sign (@), it is a global +ID; everything starting from and excluding the at sign to the end +of the ID is the ID of the cell's creation space. If the +creation space ID differs from the ID of the space the cell is in, the +cell is foreign, otherwise its native. + +

+Cells may +be connected to each other along dimensions, +so that each cell can be connected to another cell in two directions +(negative and positive) on each dimension. +The more global structure is not constrained: any two cells can be +neighbours on any dimension, but some of these connections are used +for interpreting the structure into views and actions (see below). + +

+It is not yet clear whether dimensions are strings or whether they +are cells. The various slice and compound space +implementations will probably affect and depend on this. +If dimensions are cells, then several uniqueness problems are quickly solved, +but their being strings may be easier on the users. + +

+One important point is that of headcells: on non-circular ranks, the headcell +is the cell at the negative end of the rank. +Ted specifies that all ranks should have a headcell and that there should +be a way to specify the headcell of a circular rank. The exact mechanisms here +are as of yet unclear. + +

Dimension-oriented view

+ +

+An important way to describe the space is to take dimensions to be +"objects": the dimensions are +invertible mappings between cells. This is opposed to the immediate way +of thinking "cell and connections", and there is a difference. + +

+This view is important because here it is easy to discuss special dimensions +that have interesting properties. + +

Subspaces, closed cell sets, closures

+ +

+ The following terms may prove useful from time to time: + +

+

+
Closed set of cells
+
+ A set of cells C is closed with respect + to a set of dimensions D if and only if all neighbours of + the cells in the set C along the dimensions in D are also + in the set C. +
+
Semiclosed set of cells
+
+ A set of cell C is semiclosed with + respect to a set of dimension-direction pairs D if and + only if all neighbours of the cells in the set C along the + dimensions and their associated directions in D are also in + the set C. +
+
Closure
+
+ Let us have a set of cells C and a set of dimensions D. A + set C' is a closure of C with respect to + D if and only if it is a minimal closed (with respect to + D) set containing all the elements of C. +
+
Semiclosure
+
+ Let us have a set of cells C and a set of + dimension-direction pairs D. A set C' is a + semiclosure of C with respect to D if and + only if it is a minimal semiclosed (with respect to D) set + containing all the elements of C. +
+
Subspace
+
+ A subset C of the set of cells in a ZigZag space Z is a + subspace of Z with respect to a set of + dimensions D, if and only if C is closed with respect to D + in Z. +
+
Proper subspace
+
+ A subspace C of a ZigZag space Z is a proper + subspace if it is closed with respect to the set + of dimensions D which contains every dimension of Z except + d.cellcreation. +
+
Semisubspace
+
+ A subset C of the set of cells in a ZigZag space Z is a + semisubspace of Z with respect to a set + of dimension-direction pairs D, if and only if C is + semiclosed with respect to D in Z. +
+
Generated subspace
+
+ A set of cells C in a ZigZag space Z and a set of + dimensions D are said to generate a + subspace C', which is the closure of C with respect to D + in Z. +
+ +

XXX: are these definitions OK? + + +

Key structural mechanisms

+ + +

Cursors

+ +
+The path from the viewcell viewspx +to the cell the cursor of the view points to A +via the main cursor cell C which may or may not be the +same as viewspx. +C is at the negend of d.cursor-cargo +from viewspx and the accursed cell A is +at the negend of d.cursor. +
+ +

+The viewcell points to a particular cell where its cursor lies. The idea +of cursors is not restricted to cursors of views but, as we shall see +below, anything where selecting a single cell is important. This makes it +possible to create a new view to select that cell on the fly (see below). + +

+In the structure, a relcell is used so that several cursors can be +maintained pointing to the same cell. The path to find the cell the +view is pointing to is start at the viewcell, go to the posend on +d.mycursor and then to the posend on d.cursor. + +

+In order not to disturb other cursors, the insert operation should be +used to move the relcell to a new d.cursor rank. This operation +will leave the original and the new rank otherwise intact. +It is possible that any other operation on d.cursor will +be declared illegal. + +

Inheritable parameter lists

+ +

+NOTE: this is liable to change. It is only documented here for +understanding. + +

+An example of the inherited parameter traveral to find a parameter +value. Starting from start, we go poswards on d.2 +until we reach a cell with a negward connection on d.3. +We include that list and return to the main list. The parameters +that have values store them on d.1 or as cursors starting +on the parameter cell. +
+ +

+This section defines a way to inherit parameter lists based on the +structure. + +

Paths

+ +

+Paths are a precursor to Clang, and allow the user to express abstract +paths in the structure. XXX See the docs for ZZPath.java. + +

Selectors

+ +

+Selectors are a generalization of paths: where paths are like +zeroth-order logic, selectors are first-order logic, allowing quantifiers +("every cell in this rank") but not quantification over quantifiers, +or anything terribly general. + +

+The point is to be able to easily describe in the structure the operation +"show also all replies to this email", where the replies are generally +connected to the original by some route. + +

+One interesting idea that may or may not see the light of day +is using inverse paths for selectors. This has certain aesthetic +appeal. + +

Views

+ +

+A view is represented by one maincell in the structure, called the +viewcell. This cell can contain text which will be interpreted as the +``title'' of the view, but this is not mandatory. + +

+XXX Since some views which contain more than one cursor are planned, +it is possible that something will change below. + +

Visible Dimensions

+ +
+The path from the viewcell to the cell specifying the Y dimension shown. +First, we go two steps on d.dims, then +use the same method as in the previous figure for getting to the accursed +cell from there. +Note that both the viewspx cell and the X have +cursors similarly attached to them. +
+ +

+Dimensions that are currently visible +are listed on d.dims from the viewcell, in order X, +Y, Z (and possibly others, in case of complicated view rasters). The +dimension cells are treated as cursors, i.e. the cell representing the +dimension is found by going to the posend on d.mycursor and then +to the posend on d.cursor from the dimension cell. + +

+The point of this odd-seeming arrangement is, as alluded to in the +Cursors section above, is that we can very simply create a new view that +is bound to a dimension cell of another view. + +

Dimension lists

+ +

+In order to change dimensions shown, the views provide an operation ``move +the X/Y/Z-dimension-selector-cursor one step pos/negwards on d.2''. +The usual plain-vanilla dimension lists are thus simply lists of cells on d.2 +which +contain the dimension name as a string (possibly by cloning). +Most often these lists are cyclic but this is not mandatory: trying +to move past the end/beginning of a list simply does nothing. + +

+This is just the default arrangement - the user is free to create other +dimlist operators and use them to change the dimensions taking advantage of the +structure in a different way. One example of an operation we may want to provide +at some point is "change dimension but not to one already being shown". + +

+To select the dimension list for a particular dimension of a particular +view, the user can simply create a new view for the dimension cursor, +using the cursor-cargo mechanism. +To set all the dimensions to the same list, the user can set the X +dimension and then invoke a special operation that sets Y to the +d.1 poswards neighbour of X, Z to the neighbour of Y and so on, on the +same list. + +

Raster definition

+ +

Vanishing raster

+XXX + +
+Getting to the raster-defining cell R from the view specs. +Note that the cursor-traversing operation is abbreviated to the curvy arrow. +Also note that the inheriting mechanism defined previously is allowed. +
+ +

+The raster to use is obtained similar to the dimensions to use; +only the first motion is different: down on d.2 until the text +FlobRaster is found. + +

+A sample specification of a vanishing +raster, specifying values for two parameters. +Here, the vanishing cell would stand in for the +R cell in the previous image. +
+ +

+The raster itself is specified using a corner list. +An incomplete list of parameters follows: +

+
shrink +
2 floats; the numbers to multiply the width and height + of the cells with. +
gap +
2 ints: the number of pixels of space to leave between cells +
depth +
1 int: The number of cell "layers" to draw. +
dimorder +
2.. ints. The precedence of dimensions. +
initmul +
1 float. If the default size of cell will be multiplied by a number + for the center cell (it is usually good to make the center cell + larger +
+ +

+There are currently some undocumented interactions to provide for +hard rasters; see the source. + +

Simple Flob Raster

+ +The simple flob raster displays flobs extracted from the structure, +on dimensions given by the structure. +The dimensions are given by attaching paths to the cells in the dimlist. + + + +

Primitive operations

+ +

Connect

+

Insert (XXX rename)

+

Mono-chug

+ +

+ This operation changes one connection. It takes two directions + and one cell as parameters. + XXX image. + + +

Bindings

+ +

+ Keybindings offer a nice way of seeing how flexible the + ZigZag structure is for programming. + +

+ Most fundamentally, the names of the keys + (e.g. Ctrl-k) are on cells connected along d.2. The + action for each key is the poscell on d.1 from those cells - this + way several keys can be bound to the same action quite easily. + +

+ However, this is not yet sufficient: there may be several + input states, e.g. with the vi editor there is the insert mode + and the command mode, and inside the command mode there is the + special mode of waiting for a motion command. So in addition + to the command, there needs to be a way to specify the next + state. Likewise, some states are similar to each other so + states should be able to inherit commands from each other in + various ways. + +

+ GZigZag uses blank cells to represent inheritance: when the + routine that searches for a key is going down along d.2, it will + go to the poscell from that cell and check all the bindings on + that dimension before returning to continue the search along + the original rank. + +

+ The cursor mechanism is useful for keybindings as well: the + current state can easily be maintaned by a cursor as shown above, + allowing the user to easily set the cursor to a different state. + However, care has to be taken here as moving the cursor in + question can render keybindings unusable, so it is better to use + an interface where the cursor can be immediately transported to + the right place (such as clicking with the mouse). + +

+ The actual structure is currently such that the bindings + cursor is the posend on d.bind of the view cell. This cursor + points to the place where the inheritable parameter search for + the next binding is begun. The cursor is set, if the inheritable + parameter's value (on d.1) has a negward connection on d.3 -- + it is set to the negend. + +

+ Additional problems arise when the same view can show + different rasters. A different visualization of a structure + often makes different means of navigation necessary, or different + operations desirable. To provide for this, it is possible to + assign a raster a list of modifications to a bindings mode; when + the mode is selected, the raster's modifications are searched + first, and the standard bindings for the mode are searched when + the binding is not found in the modifications list. + +

+ A raster can be assigned two groups of modification lists: + one to be applied when the raster is selected in the left + (control) view, and one to be applied when the raster is + selected in the right (data) view. These groups are obtained + from the same corner list as the parameters given to the raster + (see above); the text searched for is ctrlbindings + and databindings, respective. + +

+ From that cell, an intersection on d.1 and d.clone with + the current bindings mode is searched. That means that a mode + which is intended to be modified is cloned, and attatched to the + raster's bindings cell on d.1. From this cell, a definition for + the binding is searched on d.2; if none is found, the mode's + default bindings are invoked. For any of these searches, the + standard parameter inheritance (see above) is allowed. + +

+ This method is practical because it "feels" very much + like the definition of the modes themselves, as the modes are + commonly listed on a d.1 rank from the Bindings + cell on the system list. On the other hand, it's somewhat + different structurally. + +#include '../keybindings.wml' + +

Compound spaces

+ +

+A compound space is simply a way of taking one or more existing spaces +and creating a new space that is a view of these spaces combined according +to some rule. + +

Trivial, kludgy

+ + + +

Notification, events and synchronization

+ +

+XXX + +

+There are many situations where one may want to be informed about changes +to the structure, either before it happens (with the possibility of +vetoing it), or after (e.g.~to reraster a window). + +

Updating views

+ +

+Out of an email from Ted, +

+There are several issues here.  One is just the mechanics
+ of a clean method of synchronization.  The other is
+ the problem of A FEELING OF FAST RESPONSE--
+ which means, very importantly, PREVENTING the
+ non-current windows from refreshing in order to have
+ truly INSTANTANEOUS response to each user action.
+ Anyway, as much as possible.
+
+ +

+In order to ensure a speedy response, we have to consider the numbers. +There are thousands of cells. Each view shows some fraction of them. +At each time, there are probably 1-10 views open and changes to cells +will reflect in several of them. + +

+Therefore, it is probably unnecessarily slow to store the information about +which cells are seen by which views (except if it is naturally stored by the +view itself). Rather, for views, there should just be a global list which +gives the priorities with which the views get to refresh themselves. + +

+Now, it makes no sense to start updating +at each change to the structure - internally there has to be some method to +freeze and thaw the global update queue. + +

+One interesting problem here is finding which view is really the current view: +for instance, in the two-part view +Also, displaying only the central portion of the views whose cursor changes first +could make a big difference. Or the rank along which the cursor moves plus some +small number of cells. + +

Internal triggers

+ +

+However, this is not the whole story: views are not the only things that need +to be informed when something changes. +It should be possible to define per-cell triggers as well. + +

+This is possible in the Java code by passing an extra parameter, a +ZZObs to a routine that returns some structural information, +such as a neighbour, a headcell or the contents. +The ZZObs will then be called once after any of the items it is +observing changes, i.e. the return value of the function the ZZObs +was passed to has changed. + +

+The callback is not necessarily instantaneous; rather, all the callbacks +are grouped and run after the activity that caused the trigger has finished. + +

Cursor triggers

+ +

+Eventually, it should be possible to define these triggers in the structure +as well, but the best mechanism for that is not yet known. +However, for some applications these can't wait. Especially important are +cursor triggers, which do something whenever a cursor changes value. + +

+A cursor trigger is placed by placing the action (XXX In what form) +on d..cursor-trigger of the cursor-cargo cell. +These actions are queued to be called sometime after the cursor is +changed (usually before the next screen update). + + + + + +

Cell storage mechanism

+ +

Transient cells

+ +

+ Most of the structure is persistent but some parts should be + transient in order to save space and time. For example, if the + information about the rastered representation of a part of the + space (coordinates on the 2-D display) is stored in the space, + this would waste an enormous amount of space each time the + cursor moved. + +

+ The transiency is specified at the time of the cell creation + on the Java level. How this figures in the space is yet to + be decided. + +

+ The transient cells are not trivial: because of design + considerations, they can't simply override connections and have + all their connections appear deleted in the persistent space. + Instead, the persistent space should appear as if the cells + had been truly deleted using the delete operation, which causes + the cells on opposite sides on a dimension from the cell being + deleted to be connected to each other. In other words, if we + have the rank ABCDE and the cell D is a transient cell, then + this should correspond to a rank ABCE in the persistent space. + + +

Slices

+ +

+ The slice design is what Ted ultimately wants but because + it's somewhat more complicated to implement, it's postponed + until some other parts of the system clear up (most importantly + synchronization) and the existence of other types of subspaces + and their interaction. + + +

Versioning

+ +

+ A key mechanism for versioning is timestamps, which specify + moments in the past. The full state of the ZZ space + at each timestamp can be accessed through the file formats. + +

+ The past versions of cell structures are shown in the structure + as virtual, non-modifiable cells, except for the one allowed + source of modification: d.cursor. The dimension d.cursor + is a source of much headache in versioning because of its + nature but the current solution is to move past versions + of d.cursor to d..cursor-past. + +

+ The past versions of a cell can be accessed on d.version, + and the past versions where the cell's content or connections + have changed is on d.cell-version, and the past versions + where the cell's content has changed are on d.content-version. + So d.cell-version skips on the cells of d.version, + and d.content-version skips on the cells of d.cell-version. + The skipped-to cells are the first cells with + the new, changed property. + +

+ XXX Can we do d.cell-version efficiently??? + +

Stable media streams

+ +

+Referencing stable media streams is an important part of the +overall design. For the Dominica project, we need a subset of the +features. + +

+A cell may contain either its text directly or a reference to a +stable media stream - either an address or a span between two +addresses. For now, we distinguish between the two types by having +the references to stable media connected to themselves +along d.stableref (this mechanism {\em will} change later, and +is encapsulated in the ZZCell class as the contenttype routines). + +

+Temporarily, we use the address format AAnumber where the number +is simply the byte offset into the invariant media stream. Later on, +the addresses will be converted into tumblers. + +

+Given a space, it is possible to obtain a list of cells that overlap +with a given list of spans. +These can be used in various ways to display parts of texts that have +links in different ways etc. + +

+Later on, an enfiladic (tree-like) structure will be used to perform +the cross-matching of the cell lists. + + + +

Blobs

+ +

+Blobs are a stop en route to full hyperFlobs. +Blobs are basically objects whose coordinates and appearance +in 2D come somehow from +the ZZ space, according to user-given instructions, which are +themselves stored in the ZZ structure. + +

+A blob has two separate aspects: location and appearance. +The location is composed of multiple dimensions, specified in some +way by the structure, of which the user will select a subset of +two or three (or some more if using e.g. linear combinations). +The appearance can also be selected from multiple possibilities, +with different visual aspects showing different aspects of the +entity the blob represents. + +

+Throughout this section, I will use email as the recurring +example. Email is a good application for blobs since it makes +it possible to see the usefulness of blobs in a practical setting. +Everybody gets too much email. Current email programs are not +able to handle the load - first of all, they are too slow, reading +the entire mailbox every time the program is started and the mailbox +is opened. The obvious solution of splitting your mail into several +folders is not nice either --- it makes it much more difficult to find +anything. This problem is well solved by the stable media streams +in the previous section: instead of different files as folders, +folders are just sets of pointers to the original mailbox file. +The algorithmically great thing is that the whole mailbox need not be +reread at any point, only the new messages have to be inserted into +the structure. After that, the structure is a good way of accessing +the contents of the mailbox. +But I digress - back to blobs. + +

+In the world of blobs, each email would be represented as one blob. +Likewise each person and subject line (modulus Re). + + + + +

Variables and constants

+ +

+Each ``statement'' or ``expression' in the ZZ space will have +some parameters. For instance, an expression of ``headcell'' will +need a dimension and a direction. + +

+For maximum flexibility and ease, we want to be able to store the +dimension parameter in two different ways: first, as a direct cell or +clone of a cell, e.g. d.1, and second, as a pointer. + +

+For design considerations, the first thing to note about pointers +is that it would be quite powerful if we could bind a number of pointers +to point to the same cell --- just like cursors above. So why not +equate pointer$=$cursor, so that a cell is interpreted as itself +if there's no d.mycursor poswards and otherwise as a cursor. + +

Dimensions

+ +

+The whole concept of blobs (and flobs) is based on being able +to grab visualizable dimensions from various user-defined places +in the structure and throw the blobs on the screen at those coordinates. + +

+Dimensions can be defined by the blobs themselves or by proxy (e.g. +an email can have as one of its dimensions one of the dimensions +of the sender of the email). + +

+Eventually, it should be possible to edit some dimensions by just clicking +and dragging. Some dimensions, like the date of an email, should be +read-only but you should be able to drag email on an urgency dimension +or some dimensions of your own (to arrange them in a pleasing way +in space). + +

+Note that dimensions do not need to have numerical values. +An ordering can be quite sufficient and useful. +For example, a time dimension to email may be more useful if it is +not represented linearly but rather nonlinearly, based on the message +density, expanding dense places and possibly (like in billowing) places +that are near the cursor. + +

The structure of a blobview description

+ +

+When the blobview is described in the structure, there will be +one or many sets of blobs to render, as well as their connections. +Each set of blobs is described by +

    +
  • a set of rules and paths to +find the maincells of the blobs to display, starting from the +cursor of the blobview, +
  • a set of rules to find the dimensions to show +for each blob +
  • a set of rules to show each blob on the screen +(e.g.~which cells' text to draw and how to arrange it). +
+All of these can be given directly or as (cursorial) references to +other places. +In the future, they will be able to pass parameters to each other, +so that it would be possible to implement the perspective view through +cells as blobs. + +

+The connections between blobs will currently be described simply by +giving paths from the maincell to other maincells that may be shown +on the screen and if it is shown, a line is drawn. + +

A high-level example description of a blobview

+ +

+I warned you that email would be the predominant example of this +section. +First, let's see how we describe emails in the ZZ structure for +this simple example. + +

+First of all, there is the handle for each email. This is just +a cell that is used to designate the whole email. +As emails contain the Message-ID field which is guaranteed +to be unique, the handle cell will contain that string. +Poswards on d.handle from the handle cell are the header, the body +and the attachments. + +

+The header is a simple d.2 and d.1 job for the field type +and contents. However, both the email address cells, the subject +cell and the references (message ids) are connected structurally: +all of them point on d.ref to the handle of the corresponding +structure. It may be that the structure that these cells point to is +not loaded, in which case they just form a rank on d.ref without +the handle cell at the end. + + + +

ZObs

+ +

+It is going to be fairly common for a Java class to get its parameters +from the structure. +The ZOb mechanism is useful for easily creating such Java classes that +read their parameters in a standard way. +Basically, a ZOb is a Java class for which the instance variables are +defined inside a STRUCTPARAMS {} block. There is some +syntax support for specifying the number of elements required in arrays +etc. + +

+The point of the mechanism is to allow more latitude with the parameters +later: for example, inserting them into the structure with descriptions, +or caching the ZOb parameters read from the structure for larger ZOb +systems to speed up the process. + + +

Email applitude, v1

+ +

+This is a specification for the first version of the flob-supporting email +applitude. +The relevant structure is shown in the figure. + +XXX email1 + +The handle cell is connected along d.handle to the most important header +fields and the cell containing the actual content of the message. +The rest of the headers are stored in the structure but are not relevant here. + + +The message IDs connect replies together: the In-Reply-To: +and Message-Id fields: the message ids on the reply-to fields are +clones of the original message's message-id field. This makes it easy +to track threads using only the structure. + +

+The flob dimension specification is an interesting part of this problem: +it should be compatible with the other rasters but store extra information +for each dimension about where that dimension is to be found and whether +it's user-modifiable (by clicking and dragging). +Since each dimension is special, it doesn't make sense to have the same +dimension lists for flob dimensions and normal dimensions but the operation +of advancing a dimension can remain the same, i.e. advancing a cursor on +d.2. +In the flob coordinates, the cell on that rank gives the name and is +connected on d.1 to the actual instructions on how to obtain +the correct cell and label. + +

+The fourth dimension is used for finding the flobs to show, i.e. to +select the rank of references to show. + + +

Interactions

+ +

+This section deals with the interactions between the various +planned features. Unfortunately, this is one part that is not yet +fully specced but at least we're speccing what the problems are. + +(XXX todo) + + +((1, 2)) + Clones +((1, 3)) + Cursors +((1, 4)) + Versioning (access to old versions) +((1, 5)) + Slices +((1, 6)) + Content links +((1, 7)) + I18N + +((2, 1)) + Clones +((3, 1)) + Cursors +((4, 1)) + Versioning (access to old versions) +((5, 1)) + Slices +((6, 1)) + Content links +((7, 1)) + I18N + + +

Summary of special dimensions

+ +

+

+
d.clone +
The clone dimension. All cells on a clone rank + are clones of each other, meaning + that their contents are enforced to be the same and + changes to the contents of one are reflected to the + others. + + For example, clones could be used to represent the same + email address on a number of email headers, so that all + those instances of the same email addresses would be + linked to each other through d.clone. + +
d.cursor, d.cursor-list and d.cursor-cargo. +
A set of pointing dimensions. + This mechanism is used for instance by the views to point + to the cursor which is at the center of the view. Moving + the cursor is equivalent to inserting the maincell of the + view poswards on d.cursor from the new position + of the cursor (the accursed cell). + d.cursor-cargo provides a mechanism for locking + several cursors together. +
+ + +

File format

+ +

+This section describes the GZigZag file formats that store the low-level +structure. This is separate from the space description which describes +e.g. the system list: the file format is lower-level still. + +

+The file format is arranged as several layers, in order to +make it more flexible in the future. + +

Runs

+ +

+ Runs are the lowest level of the file: they specify a sequence + of changes to the structure, moving forwards in time. + +

+ The run formats given are version 0 of the run format. + +

Dimension change run

+ +

+ A dimension change run is a sequence of instructions + telling how one dimension changed between two specific times. + It contains records specifying connecting and disconnecting cells. + The structure is that of a simple hash: disconnecting only + disconnects in one direction. + +

The records are: + + + + Connect record: connect cell id 1 to cell id 2 poswards. + + nbytes content + 1 'c' (99). Record identifier. + 2..65537 Java UTF string. Cell id 1. + 2..65537 Java UTF string. Cell id 2. + + + + + + Disconnect record: disconnect cell id 1 in given direction. + + nbytes content + 1 'd' (100). Record identifier. + 1 '+' (43) or '-' (45). Positive or negative direction. + 2..65537 Java UTF string. Cell id. + + +

+ These records are concatenated with no record identifier in + between. + +

Content change run

+ +

This is the corresponding sequence for cell content + changes. + + + + + New string content for a cell. + + nbytes content + 1 's' (115). Record identifier. + 2..65537 Java UTF string. Cell id. + 2..65537 Java UTF string. Text content. + + + + + New span content for a cell. + + nbytes content + 1 'S' (83). Record identifier. + 2..65537 Java UTF string. Cell id. + 2..65537 Java UTF string. Content, + as a string representation of a span. + + +

Character scroll

+ +

The character scroll for text is simply a sequence of + 16-bit unicode characters, addressable by offsets. + +

Run synchonization

+ +

+ The dimensions and content (but not scrolls), are stored in + streams that contain synchronization markers between runs + of changes. + + + + Header, identifying the file type, the content type + and content version. + + nbytes content + 4 ASCII "GZZ0". Magic "number". + 4 Java int: wrapper version number. + 4 Java int: content type. + 42 = dimension + 43 = content + 4 Java int: content version. + + +

+ After the header, the actual data starts. + The data is given in runs: + + + + Run: A single run between timestamps. + + nbytes content + 1 't' (114). Record identifier. + 4 Java int: timestamp number. + 4 Java int: number of bytes to follow. + 0..2147483647 + The run. + + +

+ Only the last timestamp before which changes occurred is stored: + empty runs are not necessarily stored except for the content file. + The time the save was done could be saved in a cell with the ID + 'savetime' to facilitate backup recovery by time. + +

Stream set

+ +

A stream set, then, is a container for all of the above + things, with streams named by unicode strings. + +

Currently, this is implemented simply as a directory, which + means that using non-ascii characters, or anything that's not + alphanumeric or dots or slashes is a really bad idea. + +

Later, it will probably be a single stream that encapsulates + the other streams; it may even be that runsynch and streamset + will be combined later on. + + + + + + + + diff --git a/Documentation/Syntaxless/synt.wml b/Documentation/Syntaxless/synt.wml new file mode 100644 index 0000000..974b98f --- /dev/null +++ b/Documentation/Syntaxless/synt.wml @@ -0,0 +1,100 @@ + + + + + + The case for syntaxless languages +#include '../wmlinc/article.wml' + + +{: [[s/(?)\b(d\.+\w+)/\1<\/code>/g]] +

The case for syntaxless languages

+
$Id: synt.wml,v 1.1 2000/09/17 23:50:51 tjl Exp $
+ + +

+A manuscript-in-progress about syntaxless languages such as Clang. +Intended for eventual publication in an academic journal. + + + +

Introduction

+ +

Computational structures

+ +

+The most pervasive computing paradigm of today is that of +directories and files, and of programs written as text. +All the dominant platforms, Linux/Unix, Mac and Windows are based +on the same fundamental structure. +Indeed, the structure is so pervasive that it is difficult +for many people to even imagine a different world. + +

+However, a different world is actually not even difficult to +define and implement: choosing a different data model for implementing +an operating system, for example, is completely feasible, +as shown e.g. by XXX. + +

+In our work, we focus on the ZigZag structure, which is one alternative +to the directories-files-text model. +In ZigZag, data is contained in cells which are bidirectionally +interconnected in a flexible, multidimensional structure. + + +

Parsing, symbol tables and integrated development environments

+ +

+We will probably need to use that term in every +paper we write ;) ;) + +

+Today's computer languages are, with few exceptions, expressed as text. +Even the use of the word computer language itself conveys +the expectation that computer languages, like human languages, +is expressible in a linear form. + +

+In this context, a parser and symbol tables are +an essential ingredient of a compiler; and that a language +definition requires defining a Backus-Naur form syntax and +namespaces for various identifiers. + +

+Likewise, it is often found that using an editor which understands +the language syntax and is able to suggest completions to e.g. method +names is almost irreplaceable. Especially important is the ability +to jump from a use of a symbol to the point in the code where +the symbol was defined. + +

+However, human language is expressible as one-dimensional +because of a simple constraint in speech: time. When a language +is spoken, a sequential form is a requirement. + +

+Computer languages try to mimic human languages in several ways. + +

Syntaxless languages

+ +

+A syntaxless language is based on there being a richer underlying +structure than a simple text stream. + + +

+ +:} + + + diff --git a/Documentation/UsersGuide/Makefile b/Documentation/UsersGuide/Makefile new file mode 100644 index 0000000..89484b3 --- /dev/null +++ b/Documentation/UsersGuide/Makefile @@ -0,0 +1,15 @@ +# DIAGRAMS=linkorder.png beamorder.png + +all : ug.html ug-ns4.html newug.html newug-ns4.html + +ugdep = ug.wml ../keybindings.wml ../wmlinc/article.wml ../wmlinc/common.wml $(DIAGRAMS) +ug.html : $(ugdep) +ug-ns4.html: $(ugdep) + +newugdep = newug.wml ../keybindings.wml ../wmlinc/catart.wml ../wmlinc/common.wml $(DIAGRAMS) +newug.html: $(newugdep) +newug-ns4.html: $(newugdep) + +include ../lib.mk + + diff --git a/Documentation/UsersGuide/active.png b/Documentation/UsersGuide/active.png new file mode 100644 index 0000000000000000000000000000000000000000..b0342c6b4090244dd38e76cadd09a985a68b39e9 GIT binary patch literal 4504 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/addressbook.png b/Documentation/UsersGuide/addressbook.png new file mode 100644 index 0000000000000000000000000000000000000000..6e1853195c853f121fd836bd135bb4d52138a8a8 GIT binary patch literal 4023 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/alku.png b/Documentation/UsersGuide/alku.png new file mode 100644 index 0000000000000000000000000000000000000000..76978969873e4c904dcd0be8c235e3f5111a2a02 GIT binary patch literal 2393 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/bind2.png b/Documentation/UsersGuide/bind2.png new file mode 100644 index 0000000000000000000000000000000000000000..14cf243df34c15da5bd127e62d7e4d3972e8bce9 GIT binary patch literal 3039 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/breakkafka.png b/Documentation/UsersGuide/breakkafka.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ea943b6085109420b953b134ab16af07248f10 GIT binary patch literal 1747 zcma)*SyWR80ze-HwIfGy>(G`76r}ZtBBFv~1jMp$(h7uFL);)$Nt7X=M>4i3|j?z6=eEHY|!oiX^NP!j=~x0}t{{GG~6~+xvNc?$`Y>AwFW;)=#$r z0I)48GW2Tzuv-HFyBY_3004Y%eo6rVz&jx}F-$bT2LQmP64?O2wga%)0AnN9CKcJL zMU+Acw~cGF*`l%0?g!oP|7pyH%toRgmdU}f*%t3xMNxsH9 zugFW9nfetaKshU2hktg|j4P*cE+;2hcpc+zy_dL17nH0gcQOA_v?cHq>rVy7*$}ok zHo`R)=dpwJZb4mx4ty7c^90aPejaSPk1bH zk2cZ}L5JeeHSUVMt=$$iv#j~5yqj6m^LO08@0Li_&1}+){R_B5b$Zac9Mvo2x$;~~ zrEH0f_8D|bMyZsM?r;|#A}RcjKH&^nWD@*S8LC8_F{?yT-E?F(9od+|S8IE2A^*CL zi-8N7{^L~;ife?KxXEq-PsVO9AQ?ddiORaKlfPN7Cgn8uGhkMw>DRy$eTsDU4gB!J zST$|j(z-GBj2_X4o+YBISZSb9qD<0fIFDH?kmuATT(>3-RNsLEgbR!=3xAbq{Ms-u zYf%g_F2vAVoPH1F8Mio?w@AA$NrHn=WSfJ2(mE?pAg$Z_701@62R0Md7%0e2!aEXs znRbP>J2URKx(+d@)h&+0Omhjscl{unr}<$qw7<;duIxhm7w7h6Vkm6T&+tq`>db9? z>p`?NeQti>umc_?3~fKCC)LdaCE=;<6KD5<$|>uv%Ni#M+F2-jAg^P5D-u)~Utb2@ zdN=fk7v6Qw%jxYgPfb*MgK5A{VDvREWR<=QY=!9>JK(*TXj*@YBBZa5F5;{~9SW_X zU(FmTY@zU!gw_);6hnqABL_KCUB6slTBJy2S|Z6I{V3wo)P632{gU~`BVN|Hqv%^_ zrj~+_yc$Xq*qz@49W}hr*aG)MqN=&i&KHe6V?Zkx9k2BrJG~|zywo?6z2*+T?fZiX zE|qJu%c%s(f1Lb<5+tP3viATTP45^d8q*)bj=XhT@5Tz5-|rpEXyX#d&V0A}P6e%n zC>tp55q-~~kDHpgLTwWQv2M?lqHSEpYI^aFa4HEzxcIBJBf^B4Lut9zui*Kn3e16)Y#0s&VCQQpC#x9s&`sd_O3QZ?fO@Pg!DHTr=o{HwE$y8OL`j)uD^v?LRGk zOO{hgY}g#@p75)bsS-5QEM~`@b$}0R%5+f^C5#WD1}xvHvF_SBw4j2zo;%Eg$*O5c z?U@4~!wJs?szv^9f<}(gk>bDo^zx1P6!hb!;0({S-j>wNnqRsCms4p8I%+Z;4cC0v zISCTQ^&Jv*Z+w|YL#-jgBQBbb6ebodY2upiFe-ttF-)F{c6PgTUx>84R(}3f*=4Z4 zi>InGV$alrowd2Tn6g&QYx64ekpo7bTdG3ADVh!bk!bkJh46_V(2#iARgTmmA7aEj z8Inam`HhAgOn~{l_)h>##aw|vCcUTCf{f2y+Eg5^->fR{e)}O;*ieleIz*3S5UxyU z+rQj6fkdjk@>yNr&gA~8O#gvLcW+5EiX{4*JGhM0g;?S#1C8d+Yx<$e&36=eB@ z|E4qja>C*GIBp0Rtg4fhL~d0V+;r1@&0lFmwR1u5F3Kb|Km-Z-@$6Q|-{YM|pzf1p!gH{ei%x!^bi1=?5Z#N6zq<1rWx1kN22Lf7M5KY%BIz9J!&)+F2(zH@3TR#D5g;C)w|4 zV5CAGyOr{lDPO7VK=9l&#b=GWGoJpi@$_3ma~KS>rzT4QTZJpNtBN4;7rb GnEziR*N)Qw literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/change1.png b/Documentation/UsersGuide/change1.png new file mode 100644 index 0000000000000000000000000000000000000000..68c1f9a4b5247168eeb9958b122e7efbbb9a7cce GIT binary patch literal 1753 zcmb7@YgkkF0mcttMY&(b4~)<5Fz9rAtQ%)gtNyl{oMUNzF*$ohxfgDFm|84 zjhhVwLH5!6BjX{+!URDUE$gfx2=Xg+%Y`85i-UhT62*~sKoEova&QR3ogf^C4EGyw z0S9m73-8`YdG#ut&_||Dg2TwKdPcrvDC!6fr~HUf+hhUk#=G!u<8rEXp3^$rjgC_B()L zwAHk{91TQ~A161PekPz%K`q-vMK;5$V@QbS&jpo?X6caccVF#8G?Nm4W67`BH0#rJ z{Ozt;MU`Wf<31!5VUnHD=LjE0NG@7|CL}&1YW?jT{0vacQ_DSp+qaPTq?slwp!+RsIM#>8-49wDWqJJx_V_QvWo=) z`ffODsId9vb}HV!^BrfM6RPwYckt0>eKs3%D3#VX9XBkN%&u+u26p5J5xRso`-u}Op|DjB z{;Vbdg!8*hJ9bLa@=`Im%sU13@Z)FHbnSeZzn7jKohGtTF-1uke~yiUIo9YjvQt-4 z)@3Y|d%rhR?|!Ln<4HB0F~`T4#A>Wa!6g3ZM(0hKEjCUidn@l#)W!WDGm?~w&h4z) ztCLLP11x45D`fS2_k8u!rtiClh;%sZ0^Y#h08aAmRa_q+qE4`XPtw*SBM;vqwdIJc zdgBXbYnc=wq`v`)T*{fEnv6^z=0hzo5dvH8bXuZd+ zpcarRGb{iG^>gR5rK=4HX;1NKh?0KSRWLUnkxv%_&iP3@t9-?6$NEDmUI9!B0!khn zpl4T>(A9RD*9)G1YTNK`6ZX}yz$~sgn7;Q9^PR-m6uXFQ5Y^#7^Kc^b9MfAbl@iLj z;avW6(Uy$~Ps^8_;EQw`ebo*{XpxqAY9PoeD}N<^Ode=JqdIDgM>}LPN8+z#Ut92u z*u@**cbx10!D&bBXdpQyQRf{&Cr7?vX&fI1CeaDV#l925l}C+o)Ru7aNn2MDW^pA( z)UdP{sumD5zIzsByFcIhy->JxJtPFpNhQqW^)0XNc^+^5TeqYUw`lJUw@mN*r~X42 N9Tgkd8FAwB{{UHljluu` literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/change2.png b/Documentation/UsersGuide/change2.png new file mode 100644 index 0000000000000000000000000000000000000000..7682403ea97e7c4e5c42926ad52d389b2c263a62 GIT binary patch literal 1819 zcmbuA|38z71Hd1jy4>gbbfS+dYMi>u9hs04;SvpV`X1?g%hl!P+m?CKY@9FE>To_` zX-ub%3Y)7NkBw1cWNt|s+APVojAzc+(|XKvue(3tKJOpjzrSB^=D~2nnvZNh0svr5 zNO0g`05CHEfZ6SpD*ym+%d1SJzyNHmQ(Lbe0IX^V3EX@1{Mc-z8)e#SL(a9#;S_7L5L;VHuK3N$ioOpH zzX5hE+`Ug2$sk$`G?OgMJC80@=2USyO9O3ry;Q!F(x1BxxhU2aA+v%=Hdo&QyI2X6d9hUXnF)S_~g4;{JxKT1z3`?qZ z1_wngez^g$N51Z{`okOE;zBSK@Y0`0KUr?~v=45xuv=wiI3PX6FfA=Cr9U-^O;X>< z7{SIPknlH(pa zAL^o_Tq{iuNXgq*{2!?-Bi>`YyN#=}Mp|AVRjlu^Lay>; zw3wgXV%Xb?8bySg9d(JD%F!Xc8DcT#E3cOD&s8@+ye?anZBo2qD|lVLpCSo@5J^gd zGLUp_{`8Q^u(;Trul1vgO~K6&4BGD#L2`PuHrJDI|UurNdHv_xr1m z=~vG|-pU+EDY}yp=a%ikhmR~C1AX2NF-bhA&$f#1u72~_~1RB`%G=;_&4ND{vpIQ;2M?hYzJY8rh_KCoE#0IqQL>uTS7Tvy^D zP$xD^&J_mS{Wjw$h3?q@O;RXn!q0~+2a93vuMTL#@lzG@q0={}DwZ;%?zXZT?WxM$ z7cAdV#%d&KSR*W`Z}RW~M+we;{;f7|qmGQ$;k5YwI-a#te0_nQypG7|F>>rEE!nLC zE#$~u5pIKk@&{AKQzCbmsB|DUp6S1WnxA4InkpNl0p=W&v#Mdvu@_!y4!BijO%x7< za2Gw~S^`32w@Ii*qe{4>cWzqU`zYEY%U}a9-a>sFtFR2Zzm^{s1IO!Kq4G?%rk@Md z#ZGfFMt!BCXTDOwYdbxieOV{N5h9U9|4aQJZX%0upga%k*in~OfP$bsxA?mPA6Pj` z|6Cv8-C26Z`)4h8>$l(oZ4C3`@b)+mw-8S+jo5033>Tr^cyJ9Z0qtz%U7X);aPVYX zE=0_v=3DDuG+$Tu7zzZWJStMPwo)ji9)~2<`cQVLaGA_>*oFjf(_Lwg-Wd;m@^An= zLY0Y|-g14dZlV`tbWiy%m?U5EVEc2??zVMr15#xS>wbSE0 zU%pJ+u66I`wFs9#<;6#ILEL!d7$lw?hf<0)qJewAcq0w}N>eXqmBOi1q9zxbEb@UN zbLr1gnQ7fawf59<(!{^3>$-7Bs*V#`-~9uxt3W3j(Zv|TZo;cQ_sqm#PKPeTA@?IS zvMp2b&a2nY6bR{rD<{s9D(#U9+)|DE%c9J|du5;fMy}rNdh*VEO)u>vGTLl)39Xsn ztW=AdlzE1|E>zjNz9el*_CEK3^YC%95Bw7NVp8n&Fb4W3MVSwi>`mbQnwa$;gCpqf+$vu++@?Oe%Jy-lXhk3ICguoqrDN^ zKf&4mdb!?ZqdbpNz3a2jMG5Ijh~Ql;Gev~Kwo@BzlF=l^FI&q7_MArsvTj*t&QEe( zAafo5kj@z|UGJiwQwu$ZjUpTZ$*GC;!qm+a<%}S8bL6B!?JaX~5E9R@Sz46$T$ea2 z%CP%`ANCk#UseotB6>Gv3v=WjMLhoM*@jzFWsT868g5WN9KoHF4hq;Bl@OP-PT90x zZ+aBCVSc)PoV()nVb{90*_>bnU2rvQY5oaQtV!X@Zx>73<+30z#q4{AP2#=32KP5P ZdcD7KUw?kNSHPpcL`YD0AU7Z`_fPzq!+8Jz literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/child1.png b/Documentation/UsersGuide/child1.png new file mode 100644 index 0000000000000000000000000000000000000000..a81db92b13e7fbe3fb2c8dc204011341a2bb2d0d GIT binary patch literal 2438 zcmbuAeN>YL8^#|bKjO3U4M^P95yT2&nbAZX%ludn{2UyWg!;VcbD;tU@Kg&Yy9D}@nI3DQhb4Wghxua(P76NZcK)Qf3R?Y`^`Gs7Nox z&3?@bzv!GlHh;88)~^=$1{8b1LQ&HFCw+Hm%$-xLu-oU&X`ZwJ$~soshJ3z=>zevO zl*OoI^d?Z{)X~qFm zW;p|5en_#ACz@`*temE<8!!$b z9P3RxT3e#G8p)tw%(pFDyPAq#x#3xC^mIXp(0vcAR6F$51O8Hv2f93ZPN%jN+BJT5 z?2~b&EwfcbN4?$NLSQkIk@WSKqr>I8M-gbGQpTLzix>uo?Sw-tGzM`6adT~_<9$p( z8kF9&YZKWl-iNeBPmn`_+HM&>;}qJTT-tRC3dDwV8psEuh&C8!(pR7Z?^O+9h`eC{ zvBAo7)TJChY{mvFi>OPB^ZG$Ykv&Y?c^x?eV&k{PI)B`V7+K%Fcz(dnB4cy#@dfjrY2afNW+>8Dl0&DsePz{?acSCzG3h&)zHgToU zqy5u~fwp-ugFlI`XAF?K6p84nEp0>(b3I)wERs+91(;Yj6X)y9MT11%@&Mbg*jgmn zTVq@iONYL^50Vcxdur)rxgk~d=j*i%D{5slHSgz>!>66TXO|wA%&SKqeTN||Ny{Cdi>3jKO6Tz+B z*Y1wMEorD@w<4j-J$8<(cM)bCrL8UWg*BlMHlfIGobyzZFHGqQU-ah@WC#ApONo&B zzB|zl6>fk;!f&bZZ7G70m37BFb@X|C^Idj^O0f>DA3Cb|LF)y5s0Iyp(r9ZHODRF< zm;^JfLEw z%xPfKa_kPgUQD+!(EOak>7hvHF9}jU{euzRdfhi`na3{5i5WqK@`Pj6w#m^!aXWfvjtC_LLu_`bvOkf`D&_pZ{yo&kI2Jue(VA;HUv>#A z7Z`?h1?NojF(yh$fiNbt#TPZ1T4XLK-jmD>Y?0|-Nb!v7T-3VE0p}`J1 z_9zouh>XrV(Mn`zOgnnsSN>2h*ox&%1?jS>xS_IrzH3UisYy|QZGmv_*F?f{`=BsQ zQby}t3_15I=B?oA`qMZ^)5sQ0P*ZiT;T@UbiaGFt5aeLwNKgP#vK=Xb3)F0!BZw*_ z$V9HP19w;B=q{sS0$wNM)LijLN0*XSFXG$rpIS@^Vh_$v*-UA8Jf`1~&%T0a#q#Qv?NdGeNv}b1cMPc%wfCR;lYF~AU!{05n5a9H zb(GAN?-q?RwKH<5)p0fDTJ2u{r`T(hj>O4>){`XKzSH zWtWCVgGg4VvL!D#UX3cb_jBObo*GVJ1L+G>lc2tA5eI3MZD~R9x@7iODHXm(!D=*0WX-6< z#Qd(BgVM^nq54Yed32qY++7ET&yY4h1d}#Gaf+nSJC#p+88Q8J;9-iI-)%bC=cTPK zQxzwS%RAylgY~yY-u$2X|MESTsIO!)10-=rGd5YWfY;SE%)O{Iv?5Zv literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/child2.png b/Documentation/UsersGuide/child2.png new file mode 100644 index 0000000000000000000000000000000000000000..9c61632749c83089b82374591019f1c17237cecb GIT binary patch literal 1833 zcmb`GYfw`M0);OsSl#jv?6Qi2$W&3N;U%G946q>3m7<`cP>4(xDUT2XBmqJa1gi@X zQmhaJO;nT?G16jzkQ>65@)SY@1Zr}Vs1d^RrV!ya1d<&)v;X(Uo;knHpKs>OIVGpQ z471$6dpiICmJ#70(Ewn!3IJvgw`>Lgz_WOFHUI#hojQ3Yv_;AX0KoKXiwOWsHh{?l zXdmA(30q9u7EeFVTQw%YWMeX!(#iNc&9|(MvOWd?i?)c6pfkC$#hS=Wx!=yhn4F_5 zvtW6Ihob%94;6M>X3U%W%|uJb8;5pW`aEI#M7>-Y*uQN{e{aUtZ;7v$c3ordT){^) z+;xg|?nG@1{VA|Gsz6)ua~6g2w>ght24?Q!@MV+U^oQQY;teA~lU@w^3k*}o?KBr8 z^!<`DpEfDQ>1b$}8EEZ0-4{m}IqA@-68&sA$UYH6@EeUS%c)=W3Pf&?-o~E$VmhG> zjZS-@*$6%~A{O{Pr~8bTrX5}#lg>T+c&6O3l7)tyn&d+{-Gid2M|W!+CU^Y+X7)|? z7CcbXv%E)=n6&RDC^%D_NmF1GnX}c%XhK7mf>Qs5hb%!om9oFjI z?N3znogGSF93a7#1|wbZbuLXtN7Tz5$xZo^tuvVvUv->V+m1b}aX?RqrS!)ZxmBL9 zzlz)|ujZ_DOdDUWiK%X@+L?96i_hUeDqdR&4kA`pNPRDcP>39KMC^Y*4iU${A>;NG zMO%MnTyN|NFo>+EY>1tAQnoPqhvX3&MU=y_*4D^#9MTg7H9cJFr!yLoHEaHzxAG?2 zbo$^~ahgDd+ePSvP%XOPpIZcaUko4j7hsV=M#;E6>r-6Sd54;&h^CFN)go%U z+b2)KLwN+MDlOr*mgS`iz#ElPe=M4;6xPPaXlh~Mu!<%SUl%p~iV38uhP8qZ6aBxb zkW+9<`eqN}ykqZxO13e^R_hr?5$>A7p&jcOy6lB4xJE-HrXBL=TpXqJh*P}jeKd03 zt*2h$QtIV>=h9Ps3v6pQkP5k=*R7y&79<}bFy5{$Zc}{cnt#%k0N$wb`sWGG^ue1I zuKA&eUu5zF7w_?@jQK0!`KRyvweDb+y(Hww+72Iu9l_oC$AU=ePvr||V(;&hx{Md6 z#$7emf`bRT&K5S(wW%l48$`0Azt?n8X%CDSv3@(rrM9JWi4(5%+2r)n1 zI1BoO2?x1Gc9xPyi5j!h7@D)%o-IOkUo(|Fwem)uhTB8p&~l=YWX!Y!Jdoa7z@`Z` z3|Tc%Xm1|K{lx(cBjL-k^<3@*reRJLi9E;Tlc}*9MKrwX`*fI>Q#Ph|temIKa*xRh zaN<@lUUe6gkM(BKqoN9`BJzEgnwV7$rL<$;X77P}P8faQkyFFkf$w6BzB=PS6#6I2 zu1E^=1jYkNu~`O7zISA4iv;TO09Zhi5;3(EL^^m2fa+`@X1>)c+SJtmSgXVkc&&A= zRwEs`ylRUDrQ!4qHf%e!{Ps7xY)|cd!HUhX95l){jp_#tRToHHvh9X=&l?K2Uc3+=MY$8kS2b0G01`3BUa>I9tdC}!)}QFwhxoojzWT$Ho{5z0RP?_<4!m}A zez-U1VJ`=6)#AlXrH6^o%Bn<2^sNNnZwygS4>smWGY%4mz#$Q$OB8ZEJD)@MuESn! zZki*>{Dqw~2X^{hGHxogCM8sC-zaLxzeLx#7ynt>J1JokMf(of=T7Rw1R@EwCjZ`G zlFD4ocrk22H9_Q%lyr@t5yRq}V0lJI0!KJccxBnu(fnkkn1oB2R|qfT<~@F!)nie<2egQ_9>{bDNv_Z3pz!c%EYK{O_weXI|1~%GUq&)`da3phKT7 zw!fGDJ!ev)za4$Q-2wOMq=$la(b{8Lx|zZ$w0<@*dkouVj`E|{t^aZj0|)gK^usr` sNkWjWxKOCiq+}<-8ngcrFMhOcUGe(grTek>u71cOLca`o8ho+nKN3&0e*gdg literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/clone1.png b/Documentation/UsersGuide/clone1.png new file mode 100644 index 0000000000000000000000000000000000000000..de95db397f2aad6f130a58e4ec88ce11e1138555 GIT binary patch literal 16132 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 O0P@l*pjt`e(EkNg*DZ$t literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/clone2.png b/Documentation/UsersGuide/clone2.png new file mode 100644 index 0000000000000000000000000000000000000000..78e798ccb8a86f3445e4ab7b645d65eae34be9c0 GIT binary patch literal 17101 zcmdtKWl$Z__bu4C1a}F6T>Rqhk_30ST-@CuxCKq%V!>TQf(Q5D?!n#N-F+&*|C@Pl z-j{hZAEu_}OIKH&v#a}@wR_iE>+I?<6(wm*bTV`R05D}`B-8)^UH|~#N>Jee0B)iG zy%zugh?XA|KL9{w^qVJRBme;TT_v?#A&wTV9>&h*fR+Z8hPktgwW9+S7b^$5F%^}X zxw{}02PYe+0Gj|e6@!YBG?kOFtEm+g2P-GzG9jxh08jz45+Bq(7mhO>t=>v!-TJ#J z7-9Im4@SWI{a(9HVM1ukL@wt0A6`8@pZdq|m3ND(9St)Nt{;@!ZXp+; zZ5%#_kJ#k3f|5p89p^U@*9?q@C*h_Li}bXCpw@cu()Mt8Un*wL^4iBqoqON* z9<=?mRZvIzJW1Gi#>V}68@y^m@5Ch+=^s?-?>z{EiQUvPrqh5n3|EdNYmnWuAH=l` zMtc{%1tMqCZ2hFI`J)1URzN7v0=M3UnnpIn!6+Wj4OK`6&x4GnlCrBfBi#_Jzvs?` zUw_{g%@Ah5RV~%020eJ6HTf3#853K1NYC?}*aXU^Ms4Ib~4Zu zMATRS8~0e{&i?!oS3DHYllaW2QD<`QAMXANZ>pg%PMA&w+PI3z%ILpa$}q?g@cFFq z)!~ablgZAVSkDH=jCU)A$mgf<^QVIurw8e9C==dpN|zB<`mh^&pTO}~Yr7yH2~lH^ z-#K2okn$o683mWWGn#82-UTE>pl7P$&wPnMRMz{n9EYZHhSJ^AnM;kT=5vdj{OeRJep}8F-piY1*FYVu_*Pz}1Se`B z?G9>vg>g#OXEo&c^3w~XbLVON^7B4Xh-q>+Km9iS^PBV1luP$nvaHDO<9jLhNv(x( zLQs%6eT}oEl$kI-TZ=4 z#fX5Vr7xA~ziS40gP4T41O6MNEhctVugMf9NxEf(o6(Q{0x_R3U7i``C^Lhr%YOG> zkjJm5x2Rl^wwHqnrr`biNS|BDxn8ZZ1YM2Hem^@W+e~>^UJmT{1mG_(inTs=6)K*_ zvYFJF_qB;tT{9RjCc|!`964U}(*$^1nj1gzn6%NNr?e@)KpLLuJx_%US0AH!Gk>M} zrx?8SpyO7~`XKwhJ8p_L$jts6OuOn_pfbh69ea=(y*l41ivDwkj?fiD3qov4^GM;c*xs7n=iaBXud(`E zhbYYjYA8^;DijyP8UE=VC-K*m_eZLcMuxsI%_S3ZT%OnArprot7+p}l zYeJDm9#E>=fmnd%chw@S%o(ba7-%yCUY|O&%qIS_fo#Lm5w^F-zxYIrORt1YDir%{ zPIupI>qD<^iyz-(*xkH6Ha+)aTx-8%zdXp5$K_j6+f_11n=M4?;PU` zEse{APPw%y=9zZ6ZgJW(eb_?-O(C`>;Z*uaHGQkX8%;wl;kA-~E;0;7Jc8K_Ob#M9 zPihWUBn}h!3n)M~D~`NMeEcH5mInt*p)Q}_gn5{I%*I!x>b2Ze_i)e05C8VNM7>um z5%rrJru}@<)p*@q-4pD}bN8g+5{5MVL8DV*i=$L9yliQ*IDVukf3H-xRIZBi0C8)a z10niykhJd&C0h)rTI(C4K0^JozU0!X7J+UUI>y$YRf0*E&A*~pb{vXM0*;2Sd8uWI zt6Ljp)kVR6fzE?9f{B8Z-F7zNuZ#HV)o!}qvruim=_J0HDi*#fP=Nd)WyZDUk9x`{ zd{YihrNvzTHuOnJQRv0(spxMxsKB*{3$)>u+hTCL4^VT~=s72ZHSb4XkG62V68Dzj z_)DrE_PA=z;QMm1xdh>l_r^yx@qIUJ8nKm-D6qaP8F6n?q!4uf^O{#-cyoF2O1e&d z#idMUD#1TEd^OxM?c);-E5msX<6Ug|!;s14{r@H@;^a0?)&35cn12rPu`LSCAUgeT@qJW8CDON9K?+VAx8QCvCMgX zch(@iU-5@Evst6NKQv=@xj(g+5Pt#wUS)e$K^;%4M4?^B9DW9jU!jp2P&!hp9&Eh;WI@7iXPgK#LfblCvB>P zR|;Hm$DWx#?OWfCojv~QCu`gEj>HNDv$E2kn{{oU3MI@OSoCf&O#bQ^yo4#<&?A2K zmXT;=&X48!&Xg}JQB7=Fd(9FwJEkap<7b<~`t`HsDJ+7+{{Eq$V!#~=Iw@h@eu*2+Fv-dWeGq&4%ChoK>#NB*Ub?`st}{`@T#Cuf z#_u`{g{r=0{FocLy~eLG?VFed!LG!adzCH4-C9qe8~Bc+(K&*=QUcA+u(_zvl{EeH z1=tAfX-@+B)=WXYbJLaemUo}Tm-oj;!sBZjvL`9IF{fw8S#!@j8>2)$CB~B2ob$zy z0U4XpyVHxK@3lSxzskI`JiF)Um^-GX)YClf>FDZKZA8!f+#JZJzQK^G6OU1kv1-;t zVh$tkS@`KTYFo0xn#!d`O*M(VHwQuwYe`Jr0B0X(qUfIxV&YhaoMjVIYIW z5{GcNp`g`!J2RxZ1en_*_mG#=&Zh|?-zQ$pl22)GA`F-kWj{FBb+JDcA4>Np7q_#cc=zRX2pqRNCWeuzI=1vDyeSN^h^!iR zc(~SQ!u+{<%XhF^TK_uMdb77M9idsi+*)_(yxabQAW?Jc>}dFfavD}>P(HpqdMf(o zg<<~uj=cJq_;9FXsv&bLk)|Wkw=%sICvh8^Ch*BLUg-MaZYFs7C;k3>`A7n3@&ozn z$lbN=RdmZEx2i@7mg1U0A-_oyVxM=^-p`e>mr;^0o>7IG$yn6j#fzzh{AT*=ua&aJ z-F9K z66(}`b9A9sX<6s%!J&}V?1g*x(C@B_)1^ZvgW@gI@|#1$!%ajK#rQC#QEPQ*IR96-< zm9kfI18u0!&eRlG9nOVrm~nv%mDp5EdI{uV#a^u;Mn;T&Qdt}X1L_Ba6EX7*hsHwh z+<&YI3)3a!JAdOg=e;HHD?^;}9$3xQFhBPTR8hMtCSX%{`Z9p@Sj^3)-v3~aexZ+B z8^ec#*z6a;`t`R3ETkdebp*sfb(2W~k zpn+JA%&2$*fFvTP6mz$$=fUNJG1;Nk0Y!2M3ef-Mq4$fSla^&;kyQle7kIj@-|MmI zf8Et%6Stl@Y4<Lg zxJJp#*X0KpV+6f1vS$AYZhOH`-*X5f{)2}rBB1J;2pM-GvsDx&>FVCx_*W~t>qT44 z&&IkcQ=D0AvK&j&O+%$dlCqzXVhC&br9!yho`OmFqS1Y!c4SzSWr6nqq{pIk;8{J9 zvDY`z@wF&Cn9#3yVkuGEsjc`ecZQTRbVM&K*7M$b+>J$SK(Y48d`fOnA zg{Sep$5WM?@8GgC^?2I%AScQyo8NbZSpFW$5gG=v_C^a$`&eG}PPqxYLs(9!xwM6#d z2iX^kN%d`OJW}iQI+_SE-CvUu5)cTaCabPSi-u!*>7M2?RTAMx)ksR@Rq(T-;Gs5VPZKb-Xk=d&`pZ zs_o<0JQ{ok^&el=;2~)7GQnXoq|~LfLJB`EJsFQ^QbqY#;F&x$@<$aTlvzdwGZTfC z8P}ak!F0y&6%C5#`@gTKxqh|(N-L3qj2T}YigKcF#r0di0AKjx(EYT6?OM%%D&=B4eLu)5=9ZK zs(zi=&3-xek}j5(mY3-xvCq`iu7R*Q$&KRj6-q93cPrJ)yYW-+Zv>BrqcUal=I?b{Tb^7m_fd$&JRkO~Z3`r? zSHAO(%jZ5zr0KgOIN~4Sk<)`VbjuXe{gUVDJPDJio>j3Xj;@ZvCh2$lI6XYJPfCUA ztwIYudP;C{qi`rrh+K~!YD>i&+&o?q)xs|zYspRNPoF@bm*{8Z)olLxD+n*c?3MI; zn-;5<`%J#sG+Uw7lbS{Q2LngxbgN{mDf8q{TWGH$xVSAetQxL!w5{WhG@xsNHs34! zhfUVnzd|*a$A6a-n(3)6ul9@4DjRQi?1*<3uAX*~p)@XDTGHqWO=QTK!5eA0hMP|qmWo5v z#79SlMRmADwFMtiuxXDCWx0wJu|c_ElpeQdi6?{+ihNTQe}>YN!~PT#v*F;r9$9!? zKEJWiTHbaUqgf>v^8X<*8POE&j}fXrDC(%6x6W;4qTzL5qvPm*nOKXnnJ1<71`%jV zz-=PRhOou7zcWg1V89+I{jF+s*vZ|gGhxA=MLw73>snZGPeet+t36VX$)wz6J*Hdj zse%P`okgXO5du4bWdJ+2D^h@04ihkppbuyCZVw%}6xRe&Q2xNT3;#cvVmkW}_&K!^ zFV5)Rd%OTOB+mIT9A?4#$a>P!JY~4!d(Jzue5O?A8MgD6SRYe`1w4VJXJAqs4lpE5 zJTifF3{2n*jfk+i3e;$`q=_}2T>VTQz{&OO@z{t8NH>h1aKS5V>JoJ&B z6Yk>I(jUPG1JAU7UP6-59YcK?Y;Rs;4AwLL83Qi}zOb_a38;h9hcn6o@5yoBjBO#@ zs37Twv1&L;zX=d#ylv>I9u3Q?h(QFlln9>)fjZ;lws1GGa78IFz9TJLQphAM?zagW zW4*j4!L45c6H7tp0i7v*co|Mkt%b~N{W?a9+s%gE;k~=~L*=KR^`b3M*V-U)AspZ` zL0QwT>XDB`{;RQjgf+hcKkWz)l<;sN@JIiPnx;-94FB`qpu2=EdyS$N=HPC*YXcK- zWGb^oQ#oYV(@ME5H-w5nI1`(5%;#=ZvsbNzL>(!iip=m{8|s z!ned|hX6lXfOQ2+Hq7$vhZ%x-tPFu3m@qf5OL!i^$`a=4QA9F(Yb;+iv8C>)E*x4f zR+P4%7?@S^K#nk4R~{tQTY@%$?g*02KZcS~Fr6*Jo99-Xi?9El5+8KNt7ws1EctNm zhX$bLv-{Ihd`B&Ok&YUVLkivG^tLc^@u{VxhSz}yKxzSHN#&s!`Sff_uZ?WWZP?wd8XofR_ifJWPT4c#t*AO~ z#gkL`Rb0XZk_QHUOO50WhnEo%k{?EVjD3+qr}ESkuL9CqY8}(%xAfkj0>Mj`6TSgmI*Wuye0qZqKqep%jkv_sDK{?Y8qI!=w=ZT335~$+|XJ*H2 zL?LI4G49#YHZg(#sj-bs_{=1+DNp0Upvdfp-ohr~E@v{b!9@p2IikFn&CoDdmfs}iS3D6~Is+Q?;jzc4SIyoR;64 zC9SuEQll8W#6Jm}S_YpiK4R|b(brOL_f1VD{JF=1Rw(DiWw#wfft(si z%oj!DTnbhV%yoV>d=~b$FiPsh0ZBat6|FcKGTiTj!^5}u4V+Bc%(6HLc3@wPmdGHr z+}XBrzeN*&SA0vIyG-1ag(ijdoj`xNhCu9HVQx{6vXKoZ z)YPF;a-Yo$Jm`{)cgp%}@3bsKAv=A>MC0T)!51~;{!f~U*|YIdVU7=N3+j!RLrdvF z;~WbPv5r2DcMl&KweLJXApRHi>NxI@_~nyqxq%+vScXm+7UGGKYtsdx2Tiot7D`BZ z)gjdDu56<0VAl-hOR2%G&Jg19l+ zCzV1hfx89Wju|cRTf5~_eI{ab%=y$k$IL%m5*h!Cb-nop3)mSk3kpzGnX|s%d(SY+3i6&90()hNf(`ji7CYR8|u?XE=G-Jovan0I;IhDX()Z|MZwZ zsnw!E+_t=}oXq!ficHwC^75HNbXgp z+B@28@33%R?z37);d%a>!%fZCcp^VVy_#8D)+SeP_sSoe9O@zrsYadV3G|WPlhHO3 z5-4B7NzPwBRFuQ~J*cw&5m)c3oCZf3X)sjzB?-!H>?P-^|xP-(dx;^y5LNBGWzXTzaQ(F0rFU`--KUuh#z4jlaKhyAl zKy9^w*jT^tDpv7c$xU9TqxZ4iw<_rrt)$N!(4e5~Roj}q_ILGR6TjM@uRn*1wVk^N z7Gha>u75wp!9CZ|)X6&AC6L(myDFM!MrZqZFX?iyHP!Zd*e3Sn$@ON5`S{vn8istG zvr!PAwS9*j_GNr>1;(WPA}G5LycziDdgC~n#s9_Rgx*DH^~AMppdnXn9avxBhvxM1*wK-4fRh?<(Zde=f%sI=C{wu#MS zdv=IUtPpp6dKG^fwsPauxM(XXjqaJK%<{8H)poyXomR9Ru!%g62>pM8U5 zhPK4F=#@XdGAnIrM#Ab6U>}S#;N*2mE$%uikg-Me~G@Jwo&x;fX?~qRqvn*`KVs0^(@-yKBkn(_ zJ6F8#QIVcOCg;}}rSToJ(~FHF!1kz}g<2PJAmp3VqQ9m>1J>Pu| z+Yig)GuHBoc<_4<)^iqHyzroTdgQbbo+5@mYyR`TE9bh1$GA=ud{0o@tI8$PW2FOG zk4@Ij7^p>Yrih&48S*^+i>de2hqM`F;T;(H*aT(s+uAN_cA=eyN)^7y6*7gR46U*b z_lZlj_Na7u@iN4z*jn=b%91hCre4Iu%j3{eu>RkB0no<3Z~V^HJC4iHGH59>gC8QR z*Qc=|SDt)FeNmmZaC1n}S+V}4dt@P!NGS?G&2k$p8IWz0F#dplb0@g06gpJV}pk6n7WW zRneSlFdjM2`9Mo{XCW@bxY~uE3pJB<@*p$qsuS5%(PLYSjd@i0Z#4WJ!P=R@=+azZN$t9DlNT+}C95uw1sBCm5*82jzxO6o7&X;Js8Hb_}~ei`_BAkZ%(u^1j*M^SL^5i8f1Nhr9R% z8W97I;QnnLt-}k&7dGLEY93Va`~)p^i7PuMtFhBP{vFmp`2RqVV4&_K-Oek=1_ta9 z{)J5A5-tR`;}uhb0p=fqx#;f$sHeaq)ym=H?=fN`JOL z{85)(i7z>eHm1Y1Wnj{^uj_uZVP_TiADxvMR3Wbp;HVznySJ}Ye)=hyZG^f9`EO52 zXuB`Csb$4me zSA(4)oXUCMqdnYc?YdF)i7Mju9OU|oA|1lzc8i(=bHUPHgpzre>MQJf#faSpki?pG zdWN>bf69&8yGt2f*&JDz5(yk2nd>Y@xqWMsA*!(0`HO};jDLfk(XmU}D7J7TD77lD zT?A6M&JCYGsv}y?hMq|BjL=SZaih+qStVEA0>ur;Wyra&f6BZ6{3jLitns*UoRi=Q zW$aJGyDfrGX<9E`?2&I3**PY{9pBR$FE9{T8kLUnvs91xEiNXPmzFCBY$Z^X?v@6$ zn1&YLOzYAVr$X%R@^cw2%LC*sV25$;+|BV+KuhQ^ zqx!u6I3OMosv|Dvd<;7DctA$Cng7Jt?%Wj2)fa9i32ED@rW=LYJh7!3j@GOUo^0ViHqD zQgG&p$k-V3jghr2U1jRh3uo`H$kNrBrlVJ-)g`ezcP}RFIr~|U<5>(pMr0vdtt2mH zWa2=!R)i7bEOj*L7`Hne!W3E2G8p8BH4rE)4BeotkKf2~CNTDyZeru}raQ(Xb_h8$ zX1T_41RxLy=Mxt6*r7bcZA2_sMxgP!x@E9VbAFGs%x_RXYd;au^KC;!$~T(E+j|if zDV0iXnI8mBmzobaZZZpQO}xU23>~d9M^LeE6Ednlm!`rO4333pc`$(OouY0GO@UD! zD$?t;2vB93K~fIgBIJ+ls}Nb9LuTsm4WBc4(@uAzLXmLkDzroJbK6@72sEMb%Vsl7kXox z(A-wrtX6Y{PQ-;4s?*~yu{ra-F3}ba z239|{Zu%FsGynUU*RLXatb__>H!}EauNUE;1|6<9E!a2 zm}h+m91Hnm2msDqnMz6VH$`_oNpbW@#T$>nw^sa^xLUSlMX}D4TyXuQ*s7A_VKP)m z$j+bQ`t1It{f2T;4Za+}A)n z)o@BZ0#$9Fxbe8k|7JwI{}SZ;T`l#}cN)8japT|l&$H#%YLxqG{VYn2giGJVKQVEr zi6TOfWb$h)T-Ee$+G<7hQ{wR!SlwafpQ`8u9$M2<#Y_ilH*KZR!Wp{aTjjie*XZep z1ln8d*?ppEp%~%c?!}*6U!*nnNhqju{}~fPHwlh7v1B;=Q=Zq52z9>c>~Bf(izWGJ zD^pm%@~)UyPk%ot83<)0&0cQ(%xE+uln`HAY5G8(;i9p7eM7lGkQzHGnv@y`m<#@+5SMKX*r*4dizv2PvcawuBR+BGjl{b{Tcz~oxWkT!OyC$)fD?S zE&AO5bbee1L!2)=#q5@!PSS~AD(1ZpwHCU7-0^zlvFo}!?+kc6ho%k7*p{^EL4QpT zdYDxoLijN=qy|RU4_>tmweXxbr!;Lc_a2~lxc)m5HO~ddJC4(J{KHkCJSBb=(}!&!35RI zXTu7YtydqPR-XE&9X5#NdfnNo-hE)R-}y`@MU&ZzLoU~DtzHE>`S>Cjw4`*CP%9Jz zJ%^&8xF6Nt!uIYeH+_73{Jpl=1a=P!lIHZY&>xrE>9VPAevyw=RjlISp10kw6w5y_ zO{tg&iVD?y-7j{TNPQkZsxHqSA29It!Y}?A z!7jnp5v&y~SviZsd!H@h4C6*b&@3 z_V#-r$MI6$`yj&~ce0vKhY}J;txTJT?$T(zhun4pSTDodC|*y5T7|& zDedn=7YYq}Q#5R?r4~C@q}Z4t)v&ZxzOblye0zb@GF7T^IH%h;rF_~Q`04d%b{TkW zG8q1{vFjbX3xmy3fF@cjrhaOr=haYrpLi>xO=O*nMKR~Uw%*&-zdpR@Aw`@_ zBrPRv@#3D(l#bAn@c5|Ryd0fvu%V2#CkO`F;0t|}=x#gd>*s#5on86P6oX7&HkDX} zn(9Q7q)zks{SW6i=g=~acJERpi6%CWu)TuU$AZ7sy9bFS7uAd9;qJ$4uaM|nG1Z%w zUu_YFSd8F~tKsqUqr_M(Jv7X=IV`Kfnw zn#R)K)BX5`4EI{s!k`r#XCT<+V}H^9y`%8JH+#EChNiL6mr&>iZrXb?K4do&$5fmkMiz=`fhZLyi`_%SxHWREP8elS>w$9+{VI+$ zCY=w#xumuT(g&Xo00477q=1Yl_@qNA^E%>o5vrD=S4tyno_;@!E>p+!S5^xAwKC^K z>C7M| z30hQP;CULY_E>=N*S=wUrs#I&6KgmqU%+WwvtKEbrM%|jcy})fbtNU5V-@+>__6iqf7cdLN@nTG!d0WNB4*X|j>_ea|Nc9f9*L z4O>Wo!POGF{mc5VSJqD$qr&2f&cA2v%z}MVvl>poeY!Fk2PS*sbWZgbHTnkhq`%Ze zIIyF!-+eoiFB)W)6ObH#o8e#RU2ee(!4I{3mt*5phNuTW&X=l*u_cwitx;1xadxRZ zf5-l^t++B?B5`tu6I-zL*qwGPKoFJ5u^@6Xx#r?B6F}cj!PXbk?yMGH$;?mJA6xvgG@;g+SW8UG#^8y_O`D zN>j*VBGO{$w+3VKScxMP{VYLCbQZErhCP}W`T{%VOrxtPO`bnilkSf!T6spUt&X0) z=|yY$#nsaONFKIHI~>nR&XA?6kBf$b_mATZwbwSIHRqXl=Pu)opCkPNIdlmI8elo{ zBTRR&ijrpO&CK~#am)5!x9!d$mLeO%Xns3z-e@vL0$tVbK8NjzagLvB*9R%`&DGqx z5KgP;wB?@~8lCz?0}1lhIpR6QK?dTzo>wKge9wa`GR*pu*jlJp@ZvjD3uvp^zMmPX)1lKx<&b>=8uG(m6`BrQRyX3|C9B+vb$mwp^OiWqx z3OG{+0tN#fp&INisU?s{`22fG2{-kW9Tb2;XiszgV-QC>F!hemTN4PV3jPmxiyzvG zjV7>ft&O^|0Tq$867)~$r0YBXT(3(KB$HSgKpfgZLiIl&MuNZ`^7AxRmdG{+2LR;I zeW9_!i*llT&wCB)vZMfD#PWZvq$l_t9snQ)bBOE4yki<^rvd>8{uWR`s1S zo#v%s4<88t-n9SE?+EZ(bJF&r!2yXVt%K>X(`0noy;k+Pw{A+Hn1QrUC9bm|{kav;d$IP!1+r&$~0i2yTL>LOWSh+IKX!j-()ip6XktQ&F##gooT_ z-~&_?ovL}CmHevFrQ0U6-@X^Yw@}zZ^M#Ik-jo1+EtE1Y6%AtEfdTQn{xV`Dbi`IL%x*Rd zl_?!JNd>;0h?37)oqW0&7Um$hye^y38#kpKpcEUw!n?hL8! zgm$HhUc7&R7x}f>?8s@*QVPXE*N0|Nc!?bg!1gD;8mj;RY<;@^l4x{4@tcOtIs9|o=;6fQ>Wu1!U4EzN z99?z~nbJh_$6r1yWR%}6tizY(*Jef2qX62ey7o$bZJxVo+C&y`O@f{$BF2Sp%L0x_ zIlSp+%RPK}X1m~WINhz76;a-34Y5BI1Kgvy2a-$sn>X#klMMxSZ^iVkG!X!xhr`un zMx;ePi+=5-*XviK=vnfFY7qrRn-aF*ryR~gzHBGzVor?Y@{6}lkmbakKOdJPT7{}fv~x8wYuwaKtGkOO@FG{Kyj?wFke#^|{2I%*`OB+f_SmO} z#A8?1yLQbp$P|J1hZh}x@u12V!@N>WvzSySQlc`vW|@f%`)I_2N!5mIM1VnP`WD(H zJ1G4*9lPJFX-^QqK^gv0$h&NuH`uJoxXoE!>G`1O7cJ7_MbqZJt;(A#`Qp|)T(a)0M)!<=QjcX zFi=k)X`%_!{|#fE-Jm5}y1h_XOP22rO-e-?p*>wmG;E^gV8i0LY%TAXw><}$$r z6;_q!S_KCd%TG=W>4R1#-`{)jlq&F~T51U;rSIV3QwJW5rMk>_#TIgyv`1M{No_ex zKbWg-E^7V_V1=|6{f6Uw6r~Vt^C)q@<<{YNaW= z=;}i-qA$7c7p9mx{wzEG;3ZL0q%QrpZY(2kha_k-_&FoQkZ82!OqmMA=eQb~zTJ8M zMlzeHKRtZ498c-vODY)R`5hMQ_j&RTQ@_>gmu@Cs^xh=AdA-ynPE{yDX2LuiK=lTE zQZj*4p(OFU339MzApXi+^HzXRB^`e*;%aXY*5AM?Z6-UX-M$ z2P4|EHfFCG*8#?|_J0Ml%E@%PpNqRq0}h_S9F8BC%G1))CLHt>6&0T?p3@AiH~a{9 zG_+){v&)O$WkrLuS8P?4N52$%HlUkzKRo<7l1Cb@1GaP1TEQcnEr ze#K?m@M0#7*AE>{kdMjgt(GP%i3zA)FvuI{T2>w<;n+wvD#V%V>W#;=eIv~KnfbIF zfh5nSRn86X$BB&-uGWcWg5lh$R!7*tQ2I^Q@wT7O$b;}Lj$y(}Owuq{MuQ>k6Hy^> zNjXCN1s#Few>hWhsC6z%x4*w5HusR@NPSQB|i+xxw5~;yL;KSp))? znNX*9Yv)}Ev7dJ}5|9?N$~(OS;9!gL6Wg#3zV#9-Cp(qzLt!$v`5G_{y9CZ!&uhO# z5`@U<@=g+?_eLV^U@EqajUUTeN(}9AR?)!X4p_Vq$Klf-qQIs%+q1V58A)m4mo`6^ zIqlPW@5nbL{rRZg5uQW4nsJJ=h2|Y-&$*qH+EE>5p4T^o+ zz@vnkTsqt{*jMr5j80;sX7nkM2CT(9C5VK&I|Z)sx9v_Q?)I=KdU8@0-t`k2YmbVt zh^iQy2XJ^bcku2*sm=;aIx-HAX$Q`T+)3#MqHQSo!FH0v1HR4eExdCP$Hl%*<5WzV zmcA34N#KfQmX!@9Fdw_0@h1{J)Dlb$y@6)km0A&h5fD=D+pM2yc*NmcxlAZ@Mo2Lt zf$=N%L45=>bcKyJ0ngf!YEAGxFSQ}ztV_YH-@Qmo1IK>Uu+NU3c zigL#bfE9}U5-l|usea0oH!`>ui$gy@64sx>0TSL%D$WRJz&i^mZFDWCWG2E3naXaH7{3+1?9TOYrho)j@?cX{{4epFjUlH8x zA5W`f5AxXH3VvJ^g9&BTWscjFXBQ>X*$P*FxR)wsdS@0Yek`;0;u8P>fUKmFMA=89p#Kdl|Aj{Y literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/connect1.png b/Documentation/UsersGuide/connect1.png new file mode 100644 index 0000000000000000000000000000000000000000..fecd6dd5353914fd855fa5e1c91192815bbf439c GIT binary patch literal 14604 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%0AB?Z6 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/connect2.png b/Documentation/UsersGuide/connect2.png new file mode 100644 index 0000000000000000000000000000000000000000..8180e74b695c20e0a7d6e87e511b71304310b88e GIT binary patch literal 14787 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/creation.png b/Documentation/UsersGuide/creation.png new file mode 100644 index 0000000000000000000000000000000000000000..8ef50ba250cf41d26a66b1c74660ab0b241bc3aa GIT binary patch literal 2575 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 R3jzQDAo>REtlSZP{$Kn)mIMF* literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/dimensio.png b/Documentation/UsersGuide/dimensio.png new file mode 100644 index 0000000000000000000000000000000000000000..5bbd409aa969b84d65d3333ee32971c0dfc67af3 GIT binary patch literal 2568 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 RAqav*hVR~4y*=Tpe*uBlgTnv- literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/edit1.png b/Documentation/UsersGuide/edit1.png new file mode 100644 index 0000000000000000000000000000000000000000..a1b73df41c4900696f5166515ceed2451e8bae8d GIT binary patch literal 6886 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/edit2.png b/Documentation/UsersGuide/edit2.png new file mode 100644 index 0000000000000000000000000000000000000000..db8ebbac2a90fbc19fd8632915045d0ccceb2536 GIT binary patch literal 6933 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/edit3.png b/Documentation/UsersGuide/edit3.png new file mode 100644 index 0000000000000000000000000000000000000000..c507cf013fdba3e046d2e812998d261408eb2416 GIT binary patch literal 4634 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 HJrn)~45(eP literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/extra.png b/Documentation/UsersGuide/extra.png new file mode 100644 index 0000000000000000000000000000000000000000..47d6e8ae5e09027745ef8e39373187c69861aa27 GIT binary patch literal 2368 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 iM2CNWL4S%r&Q6$I^jlfg;hf)t=xsZ#m}s zAr{mKl3;ZqfRfY%!X<=g5eO!bDpEb%qKk;YA0k2iM>vG+blcgP-I@Ki&-~{3@XR~& zet747F768tSupo6a}fkt5c>7b2n4Z%2x9klhdBs>yido|5CjR>7j|G*yGnx~h*{Q* ztEy}WVzVK(mI|}1(55OhH&&qKww2B+cklShX0u&A`?sXH_^R8*Hd`}()&U_Fu3C`W zh9C||=*}GnGP*{4E?qC!{n7R(8=tppHV2pH&)WFnrC;1Suz2ypICG^V7`wOLF*4xU z%(Qn|a)kEAjGuTQ{~A|{*}Naof^;rL9gW**b6P#sK%u=s{?$k~(ct<#E(PPuF2iHW zr~&yjb4V-)0!+E79?YX_-%_kcUAGwzU;S*M?oS|fw4idPFg_Mm=fI%#y<1ZoV(_t^usmzr>28>>D3Xo`kz3s{ zf2H*vW-c*S)XFK3zm}L>2Kd+T(m_;vW zvwfx0%nN+Sm8c=G@l0+E8^e{Jkum*yjfopKq4h(D7SL%?@Lr6an@&=-?hIIGm`(3& z=J^rE$Q9ABGr{=y9bPVMm0Ww(zdkjWmJUnU5IqZmiEM_Er*F^#%>1RYyEqz!$xlH( zaJ{1G%Oj28&NV_)p3%8lPF5>f3caTqM7NDivN47|^8Zv|km_@z3e@`${H3eZK$r6$ z{A=%j8>(UqYA{XQw`{CdsmPd14`KgKU%zj}R_GMa6s_ZBc@RaJIy?(@6w*x`xO_GR zV}!8jQVRNKTgLtMM6l8|uYFNC!hiuHZYL%jY?|ow@+{OwT6Nz*0Yh7}g*LF)at5qu zK7IpjVxA@H%%Ef7;s60cgTX%D8mUKCPm!wjf~Ke`*)a9JDj=> z^)eL2QA!@E6ix~fu_jbYo7tmQFg101)5KzY?&!Eb1?izTBQ$% z&X0!gmyI>o+kQTYqFldLoKB+C0?;aVQvyFTR~QW^oM{1)*987r^KKg#Mv9B`xKY?8 zxqmmiEYMAjKht><e|ugS42ED9`vUs0b1+08@QvM#3xD|*aR7kmB2Mu z;~&AGiI!9DUZrdEwcp8H8)_3?OQ-F_EUB%5ZxH{Yoi{ag*SKAvLtK{cOJwG}O>m4a zQzye$E5PiA%xmAm&l0F1gpMx&LZ#31U8iYq1CtcqBmlvLL?IQe;=bz(j(c-l4HhxY z37V=GfhRb_MO)D@5}{VO)9_%Fkqbmj4!tN4wesyB$;5uz3(BnT?3dnr?Hag>NW$do z{*Jv|>-O;zwA817JUB`(BB7_}bK?6%+-{7ztEW@A=wVpiOy{L7WEt+dnhfnGcRlkC8?XnLN= zhXGH_B^T?L6i+X~D67#G{=5`#m1E}@q>-XjR2d~YT*=RX;msb2dE}fCHx-z->?ax- zDtE7(sb;muHpx|^;^D!b%*!rahKFmk1z-;4?iQ$*Le7WsOF&Pj(r_KM&A*__Kb@J{l5w+F#r+jbb?#Z+3*v*(QkndA_7=2M zVVhyOqv^klvD#K)6JwWXqYhNh%;}d+(Y;4t-P8l{W8HqLCH7!u6bx8CoN3X0X%4s& zZaoGQb=iscB_BOT83PlMrHbr*q))Kth2*I^-uE+Ux$@iDX&*#)$XQWC`kTI8Ba^q% z)1-lociN6%6TbP+qX{S&7N;J_Ep&ub z%a7LK1Yr>2L2#&9#}nEm&oq4kZB@3hZo$C>T+-tBcvcqml5W}w?OE1J@A$LY#xs2k zHl4X7xM4wa`wLG+x4kJ5I(^#35Q!c2yz%P;&?oVKSjF;tpS7)Xe@!hI{l%vXzp5eZmS8?N$c2)E*W~YA3&}1I zsstm(;&Z+a@o-C4GFzI&zR~NKi7^I6)j^{ik9S-CN9F$%n=d__{bVyH_@jd9A?$yT co|*hWdGL17>AtLg$!}rkuJE0*uMVI6C)S;oO#lD@ literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/familytree.png b/Documentation/UsersGuide/familytree.png new file mode 100644 index 0000000000000000000000000000000000000000..9796cd7e2fe3e13d0898c4b5f36035d174d18fae GIT binary patch literal 4310 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/font.png b/Documentation/UsersGuide/font.png new file mode 100644 index 0000000000000000000000000000000000000000..9477a0b441411aefde836ba27297f5be882e5bfa GIT binary patch literal 1509 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/hop1.png b/Documentation/UsersGuide/hop1.png new file mode 100644 index 0000000000000000000000000000000000000000..a55e0bb302dc2a932953ab58c31ca701cfe6635f GIT binary patch literal 3036 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/hop2.png b/Documentation/UsersGuide/hop2.png new file mode 100644 index 0000000000000000000000000000000000000000..472711d95bb8da6d86f173c514da71b0b0294a60 GIT binary patch literal 3523 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/make1.png b/Documentation/UsersGuide/make1.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c913c3088a765893016c050e146381df21dafd GIT binary patch literal 747 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/make4.png b/Documentation/UsersGuide/make4.png new file mode 100644 index 0000000000000000000000000000000000000000..835e793a019a517e57417dbe90ea67a876d01e41 GIT binary patch literal 1345 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/make6.png b/Documentation/UsersGuide/make6.png new file mode 100644 index 0000000000000000000000000000000000000000..f60d9d1f115848b97b9a7fa31baa23a5d5761db9 GIT binary patch literal 1582 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 Kk2SiV|NbvMG$0xP literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/mark1.png b/Documentation/UsersGuide/mark1.png new file mode 100644 index 0000000000000000000000000000000000000000..852507676136a28c17cea4713c4f46c28808b6b5 GIT binary patch literal 2569 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/markconnect.png b/Documentation/UsersGuide/markconnect.png new file mode 100644 index 0000000000000000000000000000000000000000..c5bec25f086c3260290e83e662665b45d3fe8ab6 GIT binary patch literal 2564 zcma)7dr(t%8og+JR48$^8Wcm?k&0Civ@5BE5c?2}RMPc9iWmZfm{tlD&;-0BQIMtz zk_uIPV9=>TM+NdI1_%i+Ax4E%sd9Nn3K~;x015mcgyin9JDu6te|BfieDnSHz0Nt` znJ**4-dVPG83aM^&~|^m4}x3(1i9Q?x)6e($@J+o2!aB?{Nli_YC{DCL0C&Q20_?z z2*aQ;-L0|PC0JcGCas1GVGP3#B^}y9+W}$AJ>K*9=?YeIuY}PZ{0|6v`wZ>#PYz`C zSo#v-s~;~o`Q(?&JbrDy4#Nz|Ie+`%YK|wIeLu7JK0=#4m2eAmEv_x4GkfL+WNExcZPP$SYszOBd-I{`-uIKU^1--uh<4xI@z(eX z@LODH=P9jdhfpV(S>DD)ByCQu^334Ix%JgC+H8jl2q+m|IU!8LGV(nMuqile8BWO` zhr{gIl+yw1()tz64}B$q1QE_U)n{ql4jT4>(wrIDln1=dDr)vx{jnW=w_}7P|ywwj2Ly7wd5QAVemFhL$+g!Kv9TO(n2aIK#Xbdl zXQ{Q}_`@n{jw9Cu=w>1Zhwv2=)zRj*T1SYzv~rl#Q23M@+|vT+u`KSG!P0M|TpJdT zfa8FwPHw=S?H+T0Vmb9Cp~j@ZO(K$qA!OCqyBWr5<`^P*9MV@N&{v_c)EC~=fszI} z*3&5hlW+VnJ{{{_2_87JU2+LzU|knZ>Y9b zoj*7@z*rjkEh^^V2y>LFFyyl(L~dr$-1+V$mhq9d(NOpZI*12WxtL{0P~9X4!5N$2 zMyU(jP&hV8+R{g4>6dg_!npimcQOw}!a37IG7l~Erv2Y|88!728iqbRrE#Vq^38a# z-L~m$WGT@D$z#*+$&2*^ICS)uFdv7i@VB4kKyU}DF^`itRU2?fUII(nD=+SdVH^~2 ze`R!7I11zCVUZ}-zev+8Tmdo`5E&E459=8%c}3|VV6K~3w_fZxjb7;8o-2cwxRZHP z+j%a$I6RN@hwXQijs|Um9ly%hjK%1Bq4JR`ihNkcZ5!Ae2zRGYb0~Z;n+n##Yta5n zDc|1^!6j6BZB{^p|;@wWSu27N}@UWB!tWQVxm0@=%g#{ySpBT@`LpL7mu~4x%@y02X)_+ znI=x0NS2J6zY*4-{HRA6&!;={(SeNC0w%43d6J3bGLhq7JnBl&#do=MV?rS!AGwY? z?#~TYkLR(XO&Yi(HH>#LI z1~L35;ZQ`x;-R8r3&}jf6$(>7eW%8@N4qyNLtm>&GI=7_b(WPtA0^78czGi9R&7n8 zu7DXOOYt>3V|>kRj8`OB#%&6Ts@YrF%T*=yzS&2)yt-|Khpv%V^&hcDKCVT4ih@CB zKDg(YxGF~^hEY|bjNNrN@2_z_Zewuq?5;S($Xdfgn=8kTNG2rfT#7IFp)ZxJSDuKR zZOGTC|NK+h=OsS(X!y4pH-o>GSQl$35Hu2g8EPW{GwzmhF<7Y7J>~Rpjt@;}gL?4B zJWAD*kdi7YM^yTFfs)uPT?3Q;WOR3)r?6Rb%RxQj-&-^nXm9mqZL?3JM8+G$HLl@q z#V}Xu$}@rdZhPk>C$nFhK%}0do~C#LJE@;PAeiSqh)1y3euq$-goiGY+nGTqQXMIC zmAR_tF#@|_t!NTD8v{hnTQWADCvdgzq-H84+a`@vCo)Og%~GlIVu{a>B1*34>t7_2 zXzE!_Fd!7Y1%eT~B;%V&WJx<(KH z5>f*_?^(C1+r6HeLj-}oE~w>arNPj>|M&J)c9i&9tVy?j(p_u=n`NlI_R!ug>*j1c!eI<>i_;9pG6{f{VT>k0_-t}>rcNW6w{F+m-PTd9Wr zz0@D8?dsrh4e#5ns2|8iSl{KilX-+of`bjM!a%SZwxLOsQcHBv++~FNeDKW;LMh+) zq|A7V0)yfG(Z(!0O_(JW-q7MC1a(?$sh_!x9jAyZ^gpR#M%AY%$SQoxfJ&mN9C_}| zdhs>gV7Y^KSQg33*Jr^r)u=?X6ufz?sY&K1`{(sXZ=LTl##e2uY${+{*WcgLxCL#l z3_c2;joJh4N?))TjzbOV{W%1+dxzJc&JRWAy)BWn!B(UoU1Mf_GlRfRofL0>XL^Ik zz8ksP|B(y0i&|Hs!0pON@>yr@(ew(j#toRa_dTqaXubu#dxQxjeR0d^76K17#ZJ4gf-8_*Vz^4L+AS0(tK^Uq7 z8)tfE39uQBJ5eq5H67e!pBN}v)lciwwc8T^t90(9NSO8Md$gABSqOq4+OCMtD?g3R F{wGsKkDCAh literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/mutsi.png b/Documentation/UsersGuide/mutsi.png new file mode 100644 index 0000000000000000000000000000000000000000..a12c1cdd9ba29e3e6f3b1c6beb688d3762b7f7a1 GIT binary patch literal 2333 zcma)7dr(t%7QW&eE72mND5xu~t3cR_$RdQSueuQts#ONWgcuPO0ToPyaCt~IK7c5w zR0QH1S4$p*@GvG(UJ(LDv5*@g#0nCT8&VVbp}8b?$La1L?Q~{$=9@F;k8{rV&G-Fr z&O~h8G}F<|5rUwZlz(p620;@51WmX#Z6X9gA5zASLJ$-fvE}=X5_Kg6L3m9m-YCH# z2%iPvIAl`ZHr*@5A4u?W3A>Pu<9KvpbRZ>g-r{)|OK=FERa#T}<(2|21Wn^nHmv>r zc#rX=F8#)4hwSG+=ZWH{q?$S~GPV$QeHzFRS1M@(_mwF-jV7_)e ze4hJ6)oNqX5(m)w6xf-%PyLIsfQdSbdFxoD$Y8C~?k?sfyiXtY2M603w2ADxc*6U_ zq-~($LxIsx#4EWHLcXTwg8k{dT-y@3x{!bv=mc9)#$@tRY_aTq>LLd3Jz~G;fyJO5 zw@dzZ_)u26U3Y2x6|d<7Vu<(U8b7@!l@APCKqkcK~I=eZfF}tC_9Xmn| zJ(+MU;MbMMFUTG&I6gm?=E~krg`9<)!O7Y1Nt7Hg6X-tI)u5}2v(SFQ>V+=h2==8F zjhAQ>jK9V^FmJ*P^cMo?7jekjt9Er(mXWr!c?grUWihP=>%?Uv0>MD81xUow%^de2 zCd!T*%M4l64@}DrC5RzVJIJ3qGqx#-5D4@JB@V zU(kMIp=;jFGdv}>@VkT+DW}~3s7c89&z|UWgLNbDWv3wKs0-@wnX`e2TD@PL(CU!U zD4=k43}VtXn~(%+ckYpk*T+8%3M5%;#~;dMGeCOfDcFMg&Kw=gd@I)WuO%&KpnjQjS^ z*4kJ<1kv&Mr+<A7E2je5~6AmRUAn7Z#5mR zRw@CNsRZsq<xD>5wP(w&`Hi%jO*rnj#9%baBDfYQtf8Op~=PixJSOZlgX9*mXZPJP&k; zT+NhX(!Yd7Rws;ugc?;Bi^d_0#j&+|a^cw^G%1p_Ba2J2D~mEl;mvIv%C>{W3%dFT zICa?}%M!usw*~uG1Bcr4zVf9&_4dj&u58?%MhxI9Zd6+8#~&~PdJKC_f2l|Ws*e=; zUH_g?u)T>o6FXWRiIzPdLFAs;?eaInu8)(y{-mqUT(RuaT#V(XW8mIw$!W!{=T#x; zsrBO}q@e=PgUy#(09Q!s{P=QY)B*-;f?5f}pc>x}51+x|uc*TY zg_i^KBx1L{S7dXI9EwK!a&~3g`ZWX2sH#fvAwO~zGI~8yS*;)ry-c8?6M1=IYsRjG zKl3<4YLt6{Z~3eaUfvqNM{++f2Qys#Wumc5k%Q3{jcUhET@lOotW|whp&S&WOVxE% zWA|uNqwM+cJ}@SD7S>Qs*Z&pU#WAlsrwuco6KZNHZ1!5_P520SXYo!1bFdslr>9`8 z^4x|mih{vpgwZYMbU4elpU&pbU&+I*1$$=N4#+179v@Az(D7&oHpnY*G`dy^+;|)a_hJz&VMq4b~ zTs*39j5u`3RvF=~k{7aGMI0)!QDSOA+mEkU^PX|`x-u(oEIa43Xg}Fg>i?0d)judn znz~0*gWOCQh>C{ujy272z%FaWZ;z%mg&eHT)vspTqFSt$uqfM5i`lDDz8?JKF&yQV zxbHwl)|k`1-F3&nYhFbY8rA)9ZXW0@0M%der+#c~B!Lcb{DENM3u$8p?wLF_saUoq zM^&b?DdJXIqbGmf2G9P1^EIE`Nmz><2 zWbql{?8O`837|WJ>XeFdVv~0sr6JtMeTTCo#iOOF?3lLUG_$gK;w+H3d&H?tF;u-&!z{7>7?OoJc@qHNr{fxj;H#J>TO;So6i literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/mutsiosoite.png b/Documentation/UsersGuide/mutsiosoite.png new file mode 100644 index 0000000000000000000000000000000000000000..ece22efc20d40c62e68346fe2c707f69a8af90d1 GIT binary patch literal 2875 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 O1mPiQWOLB5!ao7@ie=6K literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/myspeech1.png b/Documentation/UsersGuide/myspeech1.png new file mode 100644 index 0000000000000000000000000000000000000000..a5e124a6a42b2761f3e190eafc3bcbc39f49052b GIT binary patch literal 1561 zcmb7^`&W{80Egc$nz@|W&1x$r)||~GFNs?!red0REzJw!vMe+$MR`*)r)4fqYU)X6 zN*udD=B?2ZkR-&{f+3ojJN>eA+By4S&p+@v&-26QVo1aDdQ#O#ngAGz2X!LYJ=V5rb(2f(*L+ zy!ReB{anpZmsamu?Gd^ny4sL;V4~IVj{zMi{7>bG;hLd`CC7D=Qm?Hwmn_O6@=td; zZSrg{+^+i##eX^XF3Sk;WW{>`k&nf&0j$!UjY(|=B}Y=F3$ju4Os-UXGCiinJbk?7 z)wfJeioUSd?F~50AH;IUsfHDIcUo}77R(a$@Yv)zo-0U1xreytrM1$+4tPGzG$n3y zK^w{!3_4qgy_ll%%i>q|74u`W_h@BXJ9Fx_ghC`Hqj>?nOEZ4!Z>-~-z%wm}3O$-% ze6$=Or}b=s#c9)njCrjW|5J_s4|yQ7c(t+T#jp zfzyUj?q5o~z#QC@L;Db-W$@DW-QRq~fpY%*1c-(siH8UG)8AtYX0Ny1a)eVjd-Qcd zDsR?_x#-&r!IYhVk7EkS6X8v0UFehilQRpgg&x>jLrnMFJ9AE}-sjY|A(8qvH9GPZ zPoGb2*g!@pF2e@?fJ1><_>)+a+v4 zhDmatK*BV&Z#=&+LNiBOEg1AIZj#II-Fqr{Uny>O7Ehd=5$;Oh&F7))pU@=`)Ukn- z`!HCX)+4aeM{OCqTYl*B7entON<&dxW)+P}Qbb9p(v~JwPCfFb{ld#k{aetEMv`}= z7l)an!fd!Qv&o@MPcc5~=j3dZBB!V%S=CJ845;thul#cJXxQwME;NE&zw})!#w%9?u zG@!_pHHD^z=-17^;j27^Lz?>(Qg8wa0c{mhrGgpveKWBMH5*PKDsP`jnd{5UYV}cQt$ged6~BOpR4Pp5S6tZrAbc83Jy;v+qmlFkT`uV|tSu6A z0fU=`SEHQ{SBhw{9bsNEQN7M?S9`jXNR5a*j=9yRERqao=1lVQo9$ud^Bm{V^3@_G zGgc0wtEHU<^m_y6qgr#9iuAOR0AUfs^gC^H-|31nuJ`_=116hC0 zC_d6ekI%^8`(#BNeZ0?L$7eYp2>L*i^qZV`?LyFyc={^LTxy)Wo>oZ;%yz_To(V?Q zJ;Z4-Br)3#9oAsjngY$FO5Po|ZCHcR)yv{Y@|Q<;6VfZqt6oNiG}I0x(&ctoha8f7 z7k_}d_(w5~5G_oM^PS#3*60Bkae(ifOlt`EFhHu!EHMiys8byrM7O{Ne z(s5TYb63r$lydj=YL;*NB!Tb3^Z)VYz6O>rNMA-c*7(RaIKGJG3$&P9Gdfq;!k)0^ z-$MU`3!cx9xt0`YUs&Tivu&N#ZV literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/myspeech2.png b/Documentation/UsersGuide/myspeech2.png new file mode 100644 index 0000000000000000000000000000000000000000..f7eda8cbbfd0a199a507c08a4dae1dbf2ecf0229 GIT binary patch literal 1769 zcmb7@Yc!h)8pmH}XLZ>zdU`>Prls4ly{U0sm!LykrbDZ4v6)be(Uiy}kp?O0=tVVk z2`W{K8FiUb+Pc)`%_~|fM1m>}l|*KcxJ2HJTVD~EJw0c)U-q0mXMZ1`56}6X|MUE_ zE(G`(=$q;T0AS$f>va(TblwAiPURSQh01PjD6MU9e1_1z|27sL%;9dm+ z{!tAAfbM-iuQS2P6ROfI)+6WL9)Y@7#Cq1B{}^xaQ@^Hnb$Hm>qYUgklS+*H^g*}l z=oP(O=wWqEo_e@oV;m;>Z$pkR57H#0-mOBosV@kLSIg6jPh%0fom#e~dQ3;w(x}|N z*a+j9#%-Z-3VUrf)wsQbAJUPd(U8NRb}gnW9E+bKh;{?yarUycEm*{UYycj9OJ}cJ z?KD^^dO)r$s6}n7CMwRd-$U9CTvQ!(qm> zTPY8hK(?y_ce3{%_NSiN@~Z7}Dh6Fb(8Hx*R{i~BwzU3fWl>@^hJ8eCCWpP0(Ianc z=NY$HjeLi8&cSMVdcJF9&-D=G^@S|AIA)(H=~s~GowUW5*1VD$9dNlC-v2{DnCEvB z!4Fq%ZVpO~;8<_l`?<8%k!t%eWUmp3G~@H7suw2*df~Xur;j=pP&Tq%uqEeI#1Ptd zzx_3JL-@{P?E%lp);W3QJY3QoC9MgRu0UT$!scZy-IIyaWX4uXgUithBIezj#s%?% zBy(NT>5b+ks2CN~DUXl|DzUADlDdK+_$~Sg_p^#)&*;bk^yhLte+K+9?cR!Y&-f*b zusFT<=!Q`G5BZHo84q)!yq%^sN(lUgK--DC>n6>TDp*YWV4Dei;9W5sSZ|AaAV;pnuJ7b%k`K~^rkxgR&dLc z$59G$7GU>Kw<4F18vmv%ESY2a;a?d^Tul(>6{4G{sVovJPRf;EEpPs{v_rs`u*Lop zHSf6EBkZ+gnCZ$pg~SHIrhgI;^eCn#dlVvJp7B)GiuO()FAd$5dV%(>`;wUF=PHbs z5_2cg0&mHU6c=?1&+aGU%@d&Y+4r#0wu(M}l`Eu4K9T_LF>$&FSmx+cz$wtz7DO3bT)@ew-G{Q{kJs`Rc0DY1U9bwcqUyHtArsf|Rd-TUBfQPw5&Zl-sG8tizmw^dPoIwP?%ybbW24jFi*E{=5~SVGJ!TFBq7)`D`CxfZDtLKZY9eiR46t0NLxjbGy2k#2ai-VV0U|~#7 zTBj^ZGLp>7M|G;*=I8!0OFln+_U_i@XLiNavn{{zlg$)-kAhxOSY#wgg@K(TDzk3L z@dIp|AU_k7V{l@f@xbi|v=c`~H20iD&b_zkyxY^aA-ks0A?Wbicfrk3mk+Q~JtPz6 z^_aN#a5_PZ7G^@Pt}eB#wi{dg{GEuR@BVl>%;`k^@1BZ83eLpG5uDwUyvRrPWZUAB z>%pv-Ci|GjzXg^0JBx$T(=E~!3O-~_a!%@LqRYT5p3If)ku+o%*bqdp10nB=o_HwL z_iH~(^VnK(8&frg{&c@-)9Xoe{dy_b%^P#h0H42u5@sB>n%XLS5XqBsVw?-W&DPY$ zCs`x&#oEz2`aTWyb4vme9pXH$GtuS>Q%&rxr7WVZgiW#Z!iyh}+S~ICmdwdB7}4BAClApA;0r-c$6$Jy_@a z^bR&_^Y0p8pXlp4T_oaY#*fT{|LM;EkHu8x#zAr)_EC3^;hoakr)ahYi?BEL&?ruK tkSYqF4iFmN6i_WheR&41AGdSLc7VmjQ2W9>T>gil-`N1KhOaJV{0nwmi?RR! literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/myspeech3.png b/Documentation/UsersGuide/myspeech3.png new file mode 100644 index 0000000000000000000000000000000000000000..bd38af8e8c077f9e3ca6fc12084f2c73f284ab39 GIT binary patch literal 1746 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 RSLeM?2KohmTInNB`xoC@#Vr5; literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/newstory.png b/Documentation/UsersGuide/newstory.png new file mode 100644 index 0000000000000000000000000000000000000000..e966cabda6685b59969cd6b768b2108ae9952140 GIT binary patch literal 5069 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 z zCn-GX3&lmtN1ZqN+pw@xrx9fA0H99~~Lv(`UAu zh8#P){J@G!*6g{ylMKpr@qs|P`bZjA7CfuI zLD(DRnpq;b+pBB*Lt*6N)3Kau+SBWD$vczucW(G>$)fjDqm%xUt)eqp*;l5{H3koV z#Z8B~g|^)_88{S-r#D87==?Y(J8iY4S}-~@s!w#K-mKZ_6LlL(3Pr5e^Ez+Eb=|t) zYuMstbg({pztG|QPtF@m=wF(kjDbd3(xC2Qq{wQ}c6g(f-P=B>6Em$l3D;@NOW*$m zB3kifw$VeZcJn&zYWE-IVUkMF!64oS$9KW(IWKzqPNvzJN1;L#t`CHog?r~sXS(^v zlQZp#m$WE|dpTt@BllfgaQir?q1fq@a3I&Rbxkee3%n2Bs`4&|>3JgNkCm7-saLab zDVuN^R0yB(#N}AuRkP*POb!rjc9ZR53=54zGvFz zSh0KlS*R9(hc1%RdK1-U&S_W$1*;n(l{$kl^e63J%NcpfcYM{#hWbrp77cW$_TL3n z`eZj{YKo+-U#-eDLFyOJBmmT~yPoD!etQ~%pv+y0R=x@}ccyAczHN?>2qP-zUx?02 z!}xBB7tPtaIpfFTT|7(&|MdnBLthrX>q=DWS!AC9>SA~|aY-e^wpd#S3T*ql_~s0o zG4p91l+O=})VuKZ)u)EfH2$+nZ(y6E8U=bc&@4q9>XJ!gyy(M zfPqRwgIKmf_JeRaPKfzboJ!iVL#9un8%Th6HEpHAlQ$-DN`lMo3Pk5uUM4@QH%&@* z`ZQ#sawP0pa>?Hqb%OWI%Feu&n>?MV7neD|a_Dz4nx2sde0J}Cpkaj6Ok>VTc zqekx=M+&qyU%PqCkU8>)&!T(l`%%D3@Lo_86m{O(mT6 za6r^8n>~PMDOYDW9A!&^Eq{uo+KCq!%}IggQ(`rjGVc`>Nt4V>WU*H5-&guH#S`Pp zoJSt6e(pG*IySat*#wR)Guj>Sg|vs5YdJSbdgXROCKHzYff)|d;>9Lv*lQTu6OH;t zh1swxRGmG;c!noNN3|5e4mbl`#E|t1c5lutg0D&8qeC{wWEamCUu=s%0i5I3-95iP z^O8)>pb!O5`>~%k7Rx^7Zm4#Nv|CZ83ShQ9IKOhiXMzsstZMY35{;|?AiUTR>`@>d zQ8)ePZigixE37fSSVZiAld3*ET1j~HiTg4vDen2dHnPIIfAvcSJ9Nj9z=A*^5F>qa Kz1n+^V*UePF>1d6 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/newstory2.png b/Documentation/UsersGuide/newstory2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd7dbea4e1bc19a9eb1644fdaca33ba24e9c6f7 GIT binary patch literal 5241 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 Gi2nh(sf=9! literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/newstory3.png b/Documentation/UsersGuide/newstory3.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd254e8f76851a2aeeb02b54f6b624e32a37f07 GIT binary patch literal 6321 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/newug.wml b/Documentation/UsersGuide/newug.wml new file mode 100644 index 0000000..5f74562 --- /dev/null +++ b/Documentation/UsersGuide/newug.wml @@ -0,0 +1,1222 @@ + + + +#include "catart.wml" + + +Instructions for the Use of GZigZag +
$Id: newug.wml,v 1.6 2001/02/07 10:29:44 cat Exp $
+ + Katariina Ervasti
+ cat@gzigzag.org +
+
+ + +

This is the third version of Instructions for the Use of +GZigZag, written by Katariina Ervasti, who is working with this document whenever +she has time. (Documentation is only ONE of my tasks.) +

+Last update on 7th of February, 2001. +

+ +{#MYTOC#} + +About this document + +

+The purpose of this document is to explain how to use the current +version of GZigZag (0.1.4). + +

If this is the first document you read about GZigZag, please read +GZigZag - A Platform +for Cybertext Experiments before continuing. The popularized +article deals with the reasons for developing GZigZag as well as the +main concepts and the advantages of the system. We assume that the +reader of this document has read the article, especially the definitions of the main +concepts, which will not be repeated here. + +

+We are interested in describing the use of GZigZag as clearly as +possible. Any comments on the content of this document are welcome +and can be sent to cat@gzigzag.org. + +

+And, since GZigZag is constantly being developed, also this document +is always under construction. We are doing our best to inform users +of the latest features of GZigZag! + +

+About using GZigZag + +

At this stage of the development GZigZag can be used as an +information manager. Using GZigZag as an information manager +does not require any programming skills. Yet, if you want to build a +specific view for a certain GZigZag structure, you need to know some +Java. + +

+The following structures (among others) have been made with GZigZag:

+

+ +

+Naturally, we have build these structures just to test the +functionality of the current version of GZigZag. In the future +GZigZag will be a foundation for - as Ted Nelson expresses it - +"a high-power personal and media system, with editing and presentation +systems that expand the state of art". +

+ +If you're interested in visualizations of the future system, see Nelson's page dealing with +Floating World. +

+Downloading GZigZag + +

+You can download the recommended version of GZigZag for users on the +Downloading GZigZag-page. +The page also includes instructions for +downloading and the commands needed for starting GZigZag. + +

+Building a GZigZag structure +

+In GZigZag - A +Platform for Cybertext Experiments we use a combination +of an address book and a family tree to make the main concepts of +GZigZag more clear. This section of the guide focuses on explaining +how the example was made.

+

+Designing a GZigZag structure +

+We started making the structure by drawing our ideas on the paper. +

+We planned the structure of the address book to be +simple: it is a list of names and addresses. The names are listed +along a dimension in alphabetical order. We decided to use d.2 +for that purpose. The addresses are connected to the names along +another dimension, and we chose d.1 for that. (Figure 1) +

+We didn't have to design the structure of the family tree from +the beginning, since we decided to use Ted Nelson's design made +for his Holm Family Demo. In this design siblings are connected +along d.children, and married couples along d.marriage. +An extra cell ("+") is used on d.marriage to make the structure symmetric, +and the list of children from the marriage on d.children starts +from that cell. (Figure 2) +

+Thus, designing a GZigZag structure is basically just thinking +about the ways cells can be connected along dimensions. +The most important thing to keep in mind is that on each dimension each cell +has two ends, a negative end and a positive end, and on each dimension +only one cell can be connected to one end. This means that +on each dimension a cell can have at most two neighbours: a predecessor, +which is connected on the negative end of the cell, and a successor, +which is connected on the positive end of the cell. +

+If you want to use the same cell on the same dimension many times, +you can use a mechanism called cloning (which is explained in + ). +

+Functions needed for building a GZigZag structure +

+Moving in GZigZag +

+Before you can start building a structure, you need some information +of how to move in the GZigZag space. +

+When you first start GZigZag, you see two windows showing the +GZigZag structure. Figure 3 represents a +window showing the GZigZag structure after starting. As it can be +seen, in GZigZag cells are represented by rectangles and neighbours +along a dimension by a line. +

+The number of dimensions in GZigZag is infinite, but only three dimensions +(x, y, z) can be shown on the screen at the same time. The dimensions used +can be seen in the top left corners of both windows. If you look at these +corners, you'll see that the default dimensions are d.1 (on the X axis), +d.2 (on the Y axis) and d.3 (on the Z axis). +

+Now, there are two cursors you can use to move in the GZigZag space, +the left (green) and the right (blue) cursor. If you look at the uppermost cell, +which is called the homecell, you can see that the both cursors +are currently on the same cell. +

+The blue cursor defines the center of the right window. The speciality +of this cursor is that in addition to navigation, it can be used for manipulating data, +for example typing text in a cell . You can use the following keys to move the blue cursor: +

+ +i +up/to the negative direction along the dimension on the Y axis + +, +down/to the positive direction along the dimension on the Y axis + +j +left/to the negative direction along along the dimension on the X axis + +l +right/to the positive direction along the dimension on the X axis + +Shift-k +up/to the negative direction along the dimension on the Z axis + +k +down/to the positive direction along the dimension on the Z axis + + +

+As you press the buttons, you can see the cursor moving in both windows +and the center of the right window changing. +

+The green cursor defines the center of the left window. The speciality +of this cursor is that in addition to navigation, it can be used for excuting commands, +for example starting an applitude.. +You can use the following keys to move the green cursor: +

+ +e +up/to the negative direction along the dimension on the Y axis + +c +down/to the positive direction along the dimension on the Y axis + +s +left/to the negative direction along along the dimension on the X axis + +f +right/to the positive direction along the dimension on the X axis + +Shift-d +up/to the negative direction along the dimension on the Z axis + +d +down/to the positive direction along the dimension on the Z axis + +

+As you press the buttons, you can see the cursor moving in both windows +and the center of the left window changing. +

+If you look at the keyboard, you can see that the keys are arranged +in diamond patterns on the keyboard, one for the left and another for +the right hand use. +

+You can also use the arrow keys to move the blue cursor and both +green and the blue cursor can be moved by pointing a cell with +the cursor of the mouse and clicking at the button of the mouse. If +you use the mouse to point & click at a cell on the right window, +the blue cursor will move. If you use the mouse to point & click at +a cell on the left window, the green cursor will move. +

+If you get lost, press ESC to return to the home cell. +

+Creating new cells and entering text +

+We started building the combination of the address book and the +family tree by building an address book. First, we created new cells +for the names of the relatives along d.2. +

+The key used for creating a new cell is +n. After pressing the n key, you have +to press one of the direction keys discussed above to +indicate to which direction the new cell is created. For example, to +create a new cell up from the blue cursor's location, press +n and i. To create a new cell up from the green +cursor's location, press n and e. +

+The new cells for the names of the relatives (Figure 4) +where created by pressing n and i five times, when the +blue cursor was on the home cell. +

+To type a name (or any other text) in a cell, you need the +blue cursor and the tab key. For example, to type the name of +your mother to the cell above the home cell, move the blue cursor on +the cell, press the tab key, type the name of your mother and then +press the tab key again. (The result of this operation can be seen +in Figure5.) +

+ +After typing the names of the relatives we wanted to add the +addresses to our address book. To add the addresses we created +new cells which were connected to the cells containing the names +along d.1. For example, to create a new cell for the address of your +mother, go to the cell containing the name of your mother and +press n and l. Figure 6 +represents the example structure after adding a cell for the address +of the mother. + +

+The addresses are added to the cells in the manner described +above. To add the address of your mother, move the blue cursor +on the cell ment for it, press the tab key, type the address +and then press the tab key again. Figure 7 +shows the example structure after typing the address of the mother. +

+If you want to make typing text easier, you can use the Edit- +window. To get the edit window on the screen, move the green +cursor on the cell, which contains the text EDITVIEW and press +enter. To find the EDITVIEW cell go to the homecell (press ESC) +and move to the positive direction from the home cell on d.2 until you get +to the cell containing the text 'Actions'. When you move to the +one step to the positive direction on d.1 from this cell you +end up in the Actions list, to which the 'EDITVIEW'-cell is connected. +

+Cloning +

+If you want to use a cell on the same dimension +many times, a mechanism called cloning is needed. +

+If you want to clone a cell, on which the green cursor is, press +Shift-t and one of buttons indicating a +direction (in which you want to place the clone). If you want +to clone a cell, on which the blue cursor is, press 't' and one of +the buttons indicating a direction (in which you want to place the +clone). +

+For example, if your mother and father have the same address, you +might want to make a clone of the address cell. You could do this for +example by moving the blue cursor on the address cell and the green +cursor on the cell containing the name of your father. After doing +this, you would press t and f. The result of +these functions can be seen in Figure +8. Notice that the colour of a cloned cell is light yellow and the +colour of a clone is dark yellow. +

+The advantage of cloning is that it makes updating easy. When +you update one of the cells containing the same information, +the change can be seen everywhere. For example, if you +change the text on either the cloned cell or the clone containing +the address of your parents, the changes can be seen in both +cells. +

+Creating new dimensions +

+After finishing the address book, we started building the +family tree. +

+Now, two new dimensions are needed for the family tree: +d.children for connecting the siblings and d.marriage for +connecting the married couples. (When you're making new +dimensions any name will do, but we are used to naming +the dimensions d.something.) +

+To add new dimensions, move to the positive direction from the home cell +along d.2 until you get to the cell containing the text 'DimLists'. When +you move one step to the positive direction along d.1 from this cell you +end up in the dimension list. The dimension list contains a cell for each +dimension, which are connected to each other in a cyclical manner. +The dimesions that are currently used (d.1, d.2 and d.3) are pink. +

+Making a new dimension simply means adding a new cell on a +dimension list and typing the name of the dimension in the +cell. Figure 9 shows the +dimension list after adding d.marriage and d.children. +

+Rotating the dimensions +

+Before we can continue our study of making the family tree, +rotating the dimensions has to be explained. The number of dimensions +in GZigZag is infinite, but only three dimensions can be shown on +the screen at the same time. This is why knowing how to rotate +dimensions is necessary. +

+The following keys are used for rotating the dimensions in the right +window: + +x +changes the dimension on the X axis + +y +changes the dimension on the Y axis + +z +changes the dimension on the Z axis +

+ +The following keys are used for rotating the dimensions in the left +window:

+ +Shift-x +changes the dimension on the X axis + +Shift-y +changes the dimension on the Y axis + +Shift-z +changes the dimension on the Z axis + +

+For example, to rotate the d.marriage dimension to the X axis of the +right window, press x until you can see the text d.marriage in the top +left corner of the window. Figure 10 shows +the right window after rotating d.marriage to the X axis. +

+Connecting existing cells along new dimensions +

+Marking and unmarking a cell +

+ +Before explaining how the cells containing the names of the relatives +were connected along d.marriage and d.children, you have to understand +how to choose the cells you want to connect. In +the GZigZag language this is called marking. + +

+ +To mark a cell, move the blue cursor on the cell you want to +mark and press m. The cell that you have marked is +now coloured red. Figure 11 shows +the example structure after marking Hippy Chick. + +

+ +Many cells can be marked at the same time. To mark another cell, move +the blue cursor on the cell you want to mark and press m. +You can now see two red cells. Figure +12 shows the example structure after marking Hippy Chick and +Happy Man. + +

+ +To unmark a cell, move the blue cursor on the cell you want to +unmark and press m. + +

+Connecting cells +

+If you want to connect two cells to each other, mark one +cell and point the other one with the blue cursor. (If you mark both +cells, they will be connected into a loop.) +

+If you want to connect three cells, mark two cells and point +the third one with the blue cursor. (If you mark all cells, they will be +connected into a loop.) +

+ +After choosing the cells (in the manner explained +above), all you need to know is the key binding for connecting the +cells. So, to connected the chosen cells, press the +- and then a key indicating a direction of the +connection. + +

+ +Connecting cells requires a lot of practice. If you make a mistake, +you can use the u-key ('undo') to delete the latest connection. + +

+ +Next we explain how the cells of the family members used in +the address book can be connected to the family tree structure. +The same result can be achieved in various ways. The method +of connecting cells explained here is just an example. + +

+ +First, we rotated d.marriage to the X axis to connect the married +couple. Then, Happy Man was marked and the blue cursor was moved on +Hippy Chick. (Figure 13.) + +

The key needed for connecting the cells is -. After +pressing the --key one of the direction keys has to be +pressed to indicate the direction in which the cells are connected. In +our example the connection, which can be seen in Figure 14, was made by pressing +- and j. + +

+ +If - and l had been pressed the result would +have been the connection seen in Figure +15. Since in the family tree design the 'dad' cell (Happy Man) +is on the left and the 'mum' cell (Hippy Chick) on the right, this +is not the connection we want. + +

+ +After this we added an extra cell (+) between Happy Man and +Hippy Chick to indicate that they are married. ( Figure 16) + +

+ +Then we wanted to connect the extra cell to the children of the couple +along d.children To do this, we rotated d.children to the Z axis. (We +kept d.marriage on the X axis and d.2 on the Y axis.) We marked Lost +Boy, Athena Dean and Big Brother and moved the blue cursor to ++. ( Figure 17) + +

+ +We pressed - and k which indicates that the cells +should be connected to the positive direction along d.children, +which was on the Z axis. + +

+ +Finally, to view the family tree we rotated d.marriage to the X axis, +d.children to the Y axis and d.3 to the Z axis. The final result can +be seen in Figure 18. + +

+ +One of the advantages of having two windows is that the left and +the right window can show different dimensions of the same GZigZag +space. The same cells used in the family tree can be viewed in the +address book in another window. + +

+Changing views +

+There are several different visualizations (views) of the +GZigZag structure. The name of the active view +can be seen in the top right corner of a window. All the +figures used in this guide so far show the address book and the +family tree using the vanishing view. +

+You can change the view of the right window by pressing the +v and the view of the left window by pressing +shift-v. Figure 19 shows +the family tree in the row view. +

+As you keep pressing v (or shift-view), you notice that +the current version of GZigZag shows four views: the vanishing +view, the strecth vanishing view, the row view and the column +view. +

+Yet, these are not the only views available. The views that are used +when the user presses v or shift-v are listed in +the Views list, which can be found by moving to the positive direction + from the home cell along d.2 until getting to the cell containing the + text 'Views'. If you move one step to the positive direction on d.1 + from this cell, you are in the Views list. +

+ To see a listing of all views, go to the cell containing + the text 'AllViews' (that is connected to the 'Views'-cell on d.2). +The list of all views is connected to this cell along d.1. +

+If you want to use one of the views listed in the 'AllViews' +list, clone the cell of the view you want to use to the Views +list. Figure20 shows the AllViews list after +cloning HTree. The HTree view can now be used by pressing +v (or SHIFT-v). +

+Most of the views of the 'AllViews' list are designed for specific +purposes. Section deals with views in more detail. +

+Making changes to the structure +

+When you are making a structure of your own, you may sometimes make +mistakes or want to change the structure afterwards. The current +version of GZigZag offers some possibilities for this. +

+Undo +

+Undo (=cancelling the last move(s)) was already briefly mentioned before. The +u-key, for example, removes the last +move of the cursor, the last connection made, the last hop, +alpha-shear or cell exchange. (The last three are explained later in +this document.) It also brings back a deleted cell. +

+Disconnecting cells +

+If you notice that you have connected the cells in a wrong way and are +no longer able to use undo to break the connection, you can +use use the b-key and one of the direction keys +(indicating the direction of the connection you want to remove). +

+For example, when making the family tree structure you may notice that +you have connected your cousin along d.children as if he was your +brother. In Figure21 Franz Kafka +is the cousin in the wrong place. Franz Kafka can be removed by +pressing b and , (when the blue cursor is on +Big Brother). The result of this can be seen in Figure 22. +

+If a cell is used on many dimensions, the other connections +still remain after breaking a connection on one dimension. In +the example given above the cell of the cousin maintains its +place in the address book. +

+Deleting a cell +

+If you have created a useless cell, you can delete it. To do this, +move the blue cursor on the useless cell and press delete . + +

+Don't delete a cell on which the green cursor is! If you +do that, you'll get a 'RASTER ERROR'. + +

+Hopping +

+When building a GZigZag structure you notice quite often that you +have a useful cell, but it is in the wrong place in the structure. +Hopping is an operation that - as the name indicates - makes a cell +hop over one of its neighbours along a chosen dimension. +

+For example, if you have arranged the names in your address book +in alphabetical order and notice that one of the names is in +the wrong place, you can move it to the right place by using the +hopping function. +

+The key used for hopping is h after which you have +to press one of the direction keys to indicate the direction +of the hop. In Figure 23 Lost Boy is in the +wrong place. Lost Boy can be moved to the right place by moving the +blue (or) the green cursor on Lost Boy and then pressing +h and a direction key. We moved Lost Boy by moving the +green cursor on it and pressing the h and c five +times. The result of this is shown in Figure24. +

+Alpha-shear +

+Another operation that can be useful when you want to move a cell in +the GZigZag structure is the alpha-shear. The hop makes a cell hop +along a dimension, but the alpha-shear moves the connection. +The alpha-shear is used by typing a and two +directions: first the direction of the connection that is moved and +then the direction into which the connection is moved. +

+The difference between the hop function and the alpha-shear function +is easier to understand with an example. So, for example, when +making the address book you notice that you have connected the address +of your sister to the address of your brother. In Figure 25 +Olympos is the address of Athena Dean, not the address of Big +Brother. +

+You can't correct this mistake by hopping because the hop function +only hops the address to the other side of Big Brother on d.1. +(Figure 26.) So, you can only correct the +mistake by using the alpha-share. We pressed a, +j and i to move Olympos to the right +place. (Figure 27 represents the result of +this.) +

+Cell exchange +

+Cell exchange is an operation that changes the location of two cells +in the GZigZag structure. First, two cells are selected using +the blue and the green cursor. After this % is +pressed. +

+For example, the family tree structure is designed so that the cells +of the children are connected to + cell along d.children from +the oldest to the youngest. If you had connected the cells so that the +oldest would be the last cell of the list and the youngest would be +the cell just below +, you could change the cells to the +right places usig the cell exchange. +

+Figure 28 shows Big Brother, who is +naturally the oldest of the children, and Lost Boy, the youngest of +the children, in the wrong places. To correct the mistake, the blue cursor +was moved on Big Brother and the green cursor was moved on Lost +Boy and then % was pressed. Figure29 shows that the brothers are now in the +right places in the family tree. +

+Navigational tricks +

+ +The basics of navigation in the GZigZag space were introduced in +Section . When you are familiar with the +basics, these tricks might help you to work more effectively with your +GZigZag. +

+Returning to the home cell +

+Currently there are two keys that help you to return to the home cell, if +you feel completely lost: +

+

    +
  1. Pressing HOME returns the blue cursor to the home cell. +
  2. Pressing ESC returns the blue and the green cursor to the +home cell +
+ +Jumping to a cell using the cell ID +

+Cells of GZigZag have an ID, the purpose of which is to help +to recognize the cells. In the current version of GZigZag IDs are +numbers and can be used to make navigation easier. +

+The ID of the cell, on which the cursor is, can be seen in the +bottom left corner of a window. The right window shows the ID +of a cell on which the blue cursor is. The left window shows the +ID of a cell on which the green cursor is. +

+The IDs can be used to help navigation in the following way: +

+

    +
  1. Type the ID of the cell, e.g. '554'. (Yes, if +you want to use this, you have to learn the IDs of the cells you +consider most important by heart.) If you make a mistake, you can use +BACKSPACE to correct the mistake.
+ +Choose one of the following depending on which cursor you want to +use +
    +
  1. If you want the blue cursor to move to the cell the ID of +which you have just typed, press g. +
  2. If you want the green cursor to move to the cell the ID of +which you have just typed, press shift-G. +
+ + +Jumping to a cell on which another cursor is +

+If you notice that you have lost one of the cursors, this +function might be useful. It brings the lost cursor to the +cell on which another cursor is. +

+To make the blue cursor jump to the cell on which the green +cursor is, press >. +

+To make the green cursor jump to the cell on which +the blue cursor is, press <. +

+Jumping to the original cell from a clone +

+If you are on a cloned cell (the colour of which is dark yellow) and +want to find out were the original cell (from which the clone was made) +is, choose one of the following depending on which cursor you want to move: +

+

    +
  1. If the blue cursor is on the clone press +o to get to the original.
  2. If the +green cursor is on the clone, press +SHIFT-o to get to the original.

    +

+ +Jumping to the end of a rank +

+A rank is one of the terms of the GZigZag language. It simply +means a set of cells connected to each other along a dimension. +For example, Figure 30 shows an incomplete +address book, in which Happy Man and Wall Street form a rank +along d.1. Also Hippy Chick and Wall Street form a rank along +d.1 as well as the cells connected along d.2 from Lost Boy to Bindings +(which cannot be seen on the figure). +

+To get to the end of a rank, press END and one of the keys indicating +a direction. For example, if you would like to move the green cursor +from Happy Man to Lost Boy (see Figure 30), +you would have to press END and e.

+ +Changing the places of the cursors +

+Sometimes you might want to change the places of the cursors.

+ +If you have an American keyboard, press ~ for doing this.

+ +In case you are not using an American keyboard pressing ~ +does not work. If you want to use the function, change the +keydinging. (See for changing the keybinding.)

+ +Curseling + +Under construction. + + Modifying the user interface of GZigZag +

+ The current version of GZigZag offers some possibilities for changing + the user interface. You can change the key bindings and the way cells + (and their contents) look like. The looks of the views can also be + modified. +

+Changing the keybindings +

+In addition to modifying the bindings of the basic functions, you can modify +the bindings of the Edit window and the bindings used for curseling. +

+To modify the bindings, go to the 'Bindings' list. You find the list by +moving to the positive direction on d.2 from the homecell until you get +to Bindings. This cell is connected to Normal mode, +Text edit mode and Cursel mode on d.1, which are +connected to cells enabling the change on d.2. +

+Say you want to change the key used for changing the places of the +cursors. Instead of ~ you want to use F10. +You move on the Normal mode list on d.2 until you find a cell containing '~'. +(Figure31.) Just replace ~ with F10. (Figure32.) +Pressing F10 should now change the places of the cursors. +

+ Changing the looks of cells and their contents (Cell views) +

+A cell view determines what cells and their contents look like. +

+By using a cell view you can affect +

    +
  • the font type and size +
  • the way fonts are displayed +
  • the background colour of the cells +
  • the width of the cells +
  • margins of the cells +
+

+As you have learned earlier, you can change a view by pressing a +certain key. The same principle works with the cell views. A cell +view of the right window can be changed by pressing F2 +and the cell view of the left window can be changed by pressing +SHIFT-F2. +

+The current version of GZigZag does not show the name of +the active cell view on the window the same way the name of the active +view is shown. The cell view that you get after starting an empty +space in your GZigZag is shown in Figure32. +After pressing F2 once, you get a cell view that can be seen in +Figure33. +

+Naturally, you can modify cell views and create a cell views of +your own, e.g. a cell view for a bad rainy day with boring grey background colour +and small font size (Figure34) and a cell view for a wonderful lovely day with +green background, big font size and huge margins (Figure35). +

+Modifying a cell view +

+Getting to know the 'Cell Views' list +

+Before you can start modifying a cell view, you have to find the +'CellViews' list. +

+You can find the list by moving to the positive direction on d.2 from +the homecell until you get to the cell containing the text "CellViews". +After this, move one step to the positive direction on d.1. You should +now be on the 'CellViews' list, which consists of cells containg the names +of the cell views. +

+If you move on the list, you notice that the current version of GZigZag +contains five standard views: "Standard Flob Factory" (which is used when +you start GZigZag, see Figure32), "Non-enlarging" +(see Figure33), "Black background", "Different font" and +"SplitCellFlobs". These standard cell views just demonstrate the different possibilities +and can be easily changed. +

+(If you take a closer look at the list, you notice that some of the cells +are coloured orange. The orange colour tells that the coloured views +are currently used in the two windows. Since the current version of GZigZag +does not show the name of the active cell view in the windows, this is the +only way to find out what is the name of the cell view used.) +

+Changing "Standard Flob Factory" to "My Grey Winter Day Standard Factory" +

+Say, you want to modify the "Standard Flob Factory". Firstly, you want to +change the name of the view to "My Grey Winter Day Standard Factory" ;-). +Then, you want to change the background colour of the cells to grey, +the font type to 'Serif' and the size of the font to '8'. +

+Changing the name +

+Changing the name of a cell view is quite easy. Just go to the +cell containing the text "Standard Flob Factory" and change the text +to "My Grey Winter Day Standard Factory". (If you don't remember +how to edit text in a cell, see ) +

+Changing the background colour +

+The state of art of "My Grey Winter Day Standard Factory" after the change of +the name can be seen in Figure36. +

+In Figure36 the blue cursor is on a cell containing the text "rcfact1", which +is an identifier cell of the programme. Every cell on the 'CellViews' list is +connected to an identifier cell like this on d.1. A user should not try +to modify this cell. +

+Figure36 also shows that the cell following "rcfact1" on d.1 is connected to a +cell including the text "bg" on d.2. The "bg" cell, then, is connected to a +cell containing the text "0xffffff" on d.1. +

+The roles of these cell are as follows: +

    +
  • +The cell containing the text "bg" (for 'background colour) holds the name of the +thing you can change (which is usually called a 'parameter') +
  • +The cell containing the text "0xffffff" includes the value of the +parameter, which in this case is the value of the background colour. If you are familiar +with the hexadecimal representation of colours used e.g. in HTML, changing the background +colour should be easy. Yet, in GZigZag '#' is replaced by '0x'.
+

+So, to change the background colour from white to grey, pick a shade +of grey from a RGB Hex Colour Chart +and replace "fffff" with an approriate value. +

+For example, if you replace "ffffff" with "888888", the result can be seen in +Figure37. +

+Changing the font type and size +

+Now you would like to change the font type and size of "My Grey Winter Day Standard +Factory", but there is a problem. If you look at Figure37, there are no cells for placing the +values of font type and size . The problem can be easily solved: just create new cells for the +parameter and values. Figure39 shows our example after adding the cells + for the font parameter and the values of the type and the size. +

+The next thing you have to do in order to change the font type and size is to type in the +values and the parameter. In the current version of GZigZag, you have to start by +typing the values . (Yes, it is rather complicated, but if you type the parameter first, +you will get an error. This will be fixed in the future.) So, type "8" (or any other value for +the font size) in the tailcell of the newly created rank, "serif " (or any other value for the font type) +in the middle cell and the text "font" in the headcell of the rank. The example after these +changes can be seen in Figure40. +

+Other possible modifications +

+The background colour and the font type and size are not the only modifications you can +make. This section introduces other possible modifications. +

+If there are no cells needed for making certain modifications, you have to create the +cells (in the manner introduced in ). +

+Changing the margins of the cells +

+Margins add invisible space inside the border of the cells, which pushes the cell's contents away +from the border on all four sides. +

+The following cells (created respectively along d.1) are needed for modifying margins: +

  • A cell for "margins"-parameter +
  • A cell for the value of the top and bottom margins (measured in pixels) +
  • A cell for the value of the left and right margins (measured in pixels)
+

+Figure41 shows "My Grey Winter Day Standard Factory" after +adding the cells for the "margins" parameter and the values. +

+Changing the width of the cells +

+You can change the width of the cells using the "widthstr" parameter. +(As you have probably noticed, the StrechVanishing is the only view +that specifies the width of the cells according to the lenght of the text +in each cell. In other views, the cells have the same width.) +

+The following cells (created respectively along d.1) are needed for modifying +the width of the cells: +

  • A cell for the "widthstr"-parameter +
  • A cell for the value of the width. (This is not a numerical value. The more text you +enter, the broader your cells.)
+

+Figure42 shows "My Grey Winter Day Standard Factory" after adding the cells +for the "widthstr" parameter and the values. +

+Changing the way fonts are displayed +

+You can affect the way the fonts are displayed on the screen by +using the "enlargefont" parameter. +

+If the "enlargefont" parameter is "true", GZigZag can use bigger +font size than specified in the font parameter to highlight the center cell +in certain views. Setting "enlargefont" to false means that the specified +font size is used everywhere. +

+The following cells (created respectively along d.1) are needed when using these parameters: +

  • A cell for the "enlargefont" parameter +
  • A cell for the value of the parameter. (The value is either "true" or "false".)
+

+Making a cell view of your own +

+You can also - instead of modifying an existing cell view - make a completely +new cell view. +

+To do this, first create a new cell on the 'CellViews'-list and type the name of +the cell view in it. (Figure43 shows a new cell (named after a song of R.E.M) +in the 'CellViews' list.) Then continue by creating an identifier cell containing +the text "rcfact1" and an empty cell, respectively, to the positive direction +along d.1. (Figure44.) After this you can start creating the cells for +the parametres on d.2. (Figure45) +

+ Changing the looks of views + + Under construction. + +More about views +

+This section introduces some of the views listed in the 'AllViews'-list. +As it was mentioned in , you have to clone the cells of these +views from the 'AllViews'-list to the 'Views'-list in order to +use them. +

+Views for hierachical structures +

+VTree, VTree with lines, HTree and HTree with lines are views +designed for showing tree structures and other hierarchies. +VTree is an abbreviation for 'vertical tree', HTree for 'horizontal +tree'. VTree shows the tree vertically, HTree horizontally. +

+The difference between the VTree and VTree with lines is -as +the name indicates - that VTree shows lines between the element +of the hierarchy. Naturally, the same applies to the difference +between HTree and HTree with lines. +

+VTree and VTree with lines +

+Say, you would like to present the organizational chart of the +Finnish National Road Administarion +using VTree with lines. +

+(The instructions given here also apply to VTree. The reason for using +VTree with lines in this example is that the writer of the instructions just +happens to like VTree with lines more.) +

+First, you create two new dimensions. You could call the dimensions +for example d.head1 and d.body1. After doing this rotate d.head1 to the +X axis and d.body1 to the Y axis. Then, change the view to +VTree with lines. Figure45 shows a GZigZag +window after these operations. +

+The board is the highest organizational unit of the hieararchy, so type +'Board' on the cell. Below the board is the director general. Create a +new cell for the director general by pressing 'n' and ',' (when the +right cursor in on that cell) and type 'Director General' on the cell. +Below the director are two units: the central administration and +the headquarters. Create a cell for the the central administration first +by pressing n and , (when the right cursor is on that cell). +Another subunit to the director general can be created by pressing +n and l (when the right cursor is on that cell). +Figure46 shows +the hierachy after these operations (and typing in the names of +the organizational units.) +

+Thus, when you are using the blue cursor, you can create a subcell for another +cell of the hierarchy by pressing n and ,. If a cell has more than +one subcells, you can create more subcells from the first subcell by +pressing n and l. +

+Figure47 shows one part of the organizational chart of the Finnish National +Road Administration after adding more organizational units. +

+After creating the organizational chart using the VTree with lines you +can view it with VTree (Figure48) and other views. Notice that the organizational +chart looks quite different in views which are not designed for +hiearchical structures. (Figure49 presents the organizational chart in +Vanishing View.) +

+HTree and HTree with lines +

+If you want to view a tree made using VTree, all you have to do +is to change the two dimensions to different axes. +

+Thus, to view the previous example using HTree or +HTree with lines, you'd have to change d.head1 to the Y axis +and d.body1 to the X axis. (Figure50) +

+In this view you can create a subcell for cell by pressing n and l. +If a cell has more than one subcells, you can create more subcells from +the first subcell by pressing n and , . +

+A view for presentations +

+If you are planning to give a presentation, you could try doing it with +GZigZag. There is a specific view called Presentation view designed +especially for this purpose. (If your version of GZigZag does not +have a cell for the Presentation view on the 'AllViews' list, make a +new cell on the list and type 'Presentation' in it (with out '- marks). After doing this make +a new cell to the positive direction from this cell on d.1 and type' Prez.R' +in it.) +

+Presentation view shows the structure of your presentation +as a list. Figure51 shows a presentation called +'My Speech'. The most important parts of 'My Speech' are +'Who am I?', 'Why am I?' and 'Where am I?'. +

+In the example the blue cursor is used to move in the presentation. +The regular keys ' i , l , , and j are used for moving the blue +cursor. Pressing , moves the blue cursor down on +the list (Figure52). When the blue cursor is on 'Who am I?', pressing + l takes you the 'Who am I?' part of the presentation (Figure53). +When the blue cursor is on 'To be honest, I dunno', pressing l +takes you to the 'To be honest, I dunno' part of the presentation +(Figure54). You can get back to the previous parts of the presentation +by pressing i . +

+After you have learned how to read a presentation using +Presentation view, you might want to take a look at the same +structure using another view. Figure55 shows +the presentation in Vanishing View. If you want to make a presentation of your own, you should +understand the structure of the presentation shown in Figure55. (The writer +of this guide thinks that a presentation is actually easier to make using +Vanishing View than Presentation view, which is just designed +for showing presentations.) +

+If you look at the Figure55, you notice that title of the presentation +('My Speech') is placed in one cell. The positive end of this cell +is connected to an empty cell on d.1. The most important parts +of the presentation ('Who am I?', 'Why am I?' and 'Where am I?') +are also in their own cells, which are connected to each other on +d.2. 'Who am I?', then, is a title of a another part of presentation, +which consists of 'Huh?', 'To be honest, I dunno' and 'Yes, it's difficult +indeed'. Thus, 'Who am I?' is followed by an empty cell on d.1 and +'Huh?', 'To be honest, I dunno' and 'Yes, it's difficult indeed' are connected +to the empty cell on d.2. +

+Do you understand the structure of a presentation now? ;-) To sum up, +a cell contain the title of a presentation (or a title of a certain part +of a presentation) is always connected to an empty cell to the positive +direction on d.1. The parts of the presentation (or the parts of a certain +part of the presentation ;-) are connected to the empty cell to the +positive direction on d.2. If you understand that you should be able +to make your own presentation with GZigZag. +

+Some applitudes +

+Nile +Nile is a writing tool of the future for people who love writing. +It will provide functionalities that are lacking from the currently +popular word processors. The very first version of Nile already +supports Ted Nelson's idea of transclusions. (See +Xanalogical Structure, Needed Now More than Ever: Parallel Documents, +Deep Links to Content, Deep Versioning and Deep Re-Use.) +

+We appriciate people who have time to test Nile and comment on it +e.g on the developer's mailing list, but we would like to remind that +this tool is NOT yet safe. So don't try writing anything +precious with it. +

+Starting Nile +

+Before you can start using Nile, you should make some empty cells. +You can think of these empty cells e.g. as cells that will rescue you if you +get RASTER ERROR while using Nile. :-) (See .) You can for example +make two empty cells above the home cell. Leave the blue cursor on +one of the cells. (See Figure56.) +

+After doing this, find the cell including the text 'SplitNileDemo' on +the 'Actions'-list using the green cursor. This cell can be found by going +to the homecell (press ESC unless you are already on the homecell) and +move to the positive direction from the home cell on d.2 until you get +to the cell containing the text 'Actions'. When you move one +step to the positive direction on d.1 from this cell you'll end up in the +Actions list, to which the 'SplitNileDemo'-cell is connected. +

+Once you have found the right cell, press ENTER. Now you should see +the Nile window (Figure57) appearing on the screen. +Then move the green cursor (on the GZZ window) on the other new +cell you have just created. +

+Writing a title +

+Click on the left or the right side of the Nile window depending on which +side of the window you want to start writing. Write a title for your text. +Figure58 shows the Nile window after clicking +on the right side of the window and typing 'Story'. +

+Writing text +

+Now that you have written a title, press enter to start writing the +actual text. You do not need to capitalize the first letter of the +the sentence if you remember to press the SPACEBAR two times +after ending the previous sentence. Nevertheless, if the first word of the +sentence is a name, you should capitalize the first letter. If you later want +to move the name word e.g. in the middle of the sentence, the first letter of the name +won't be a capitalized one anymore. To start a new paragraph, press +ENTER. Figure59 shows the Nile Window after typing +some text. +

+ Moving, activating and arranging text +

+An example. You would like to change the fourth sentence of the example text so that +"a student of communication studies" would appear before "a doctor of psychology". +

+To achieve this is, you would have to do the following things: +

    +
  1. Move the insertion cursor (which is currently at the end of the last paragraph) +near "a student of communication" +
  2. Activate "a student of communication studies" +
  3. Move "a student of communication studies" to the new place
+

+The first part of the task is easy to do with the mouse: just click on the place, +where you want the insertion cursor to be moved. (See Figure60, +which represents the situation after the move.) +

+You can also move the insertion cursor by using the arrow keys. Yet, before trying to move +the writing cursor with the arrow keys, you should learn to understand the +three modes of writing, which help you to move the writing cursor with the arrow +keys faster. You can also use the modes for activating parts of text (which is +currently done only by using the keyboard) in a more effective way. +

+The three modes are the character mode, the word mode and the sentence mode. +You can change the modes by pressing the TAB key. When you +first start using Nile, you are in the character mode. When you press the TAB key, +the mode is changed into the word mode. Pressing the TAB key after this, takes you +to the sentence mode. If you press the TAB once again, you're back in the +character mode. + +

If you want to activate words, use the word mode. +If you want to activate sentences, use the sentence mode. In our example case, +the use of the word mode is the best solution, because the phrase "a student of +communications studies" consists of many words. +

+Thus, to activate characters/words/sentences (depending in which mode you are), +use the arrow keys. If you want to activate more than one character/word/sentence/, +keep the SHIFT key down while activating. Figure61 +shows "a student of communication studies" activated by pressing the SHIFT key and the +left arrow key five times. After this, you can move the activated phrase by pressing +ALT and an arrow key indicating the direction to which you want the text to be moved. +In order to move "a student of communication studies" to its intented place you would have +to keep the ALT key down and press the left arrow key until you'd see the text in the right +place. (Note. In our current example you would also have to move the word "and".) +

+Making a Transclusion +

+The writer of our example story now decides to make an improved version of her +story. To start another version, she clicks on the right side of the Nile window, writes +a new, improved title for the story, a totally new first sentence and a beginning +for the second sentence. (See Figure61.) After this, the +writer of the new version decides that the first sentence of the first version is usable and +wants to make a transclusion. +

+To make a transclusion the writer activates the sentence in question, clicks with the mouse +on the place where she wants the transclusion to be made. In our example case the writer +clicks after the ','. The key binding for a transclusion, then, is +CTRL+T. Nevertheless, because of a bug, the result is not quite +what the writer wanted. As Figure62 demonstrates, +the transclusion did not end up in the right place. (The bug WILL be fixed.) So, all +the writer can do, is to move the sentence to the right place using the method introduced in +. The text after the move (and another transclusion) is seen in +Figure63. The use of colours demonstrates the parts +of the texts that are the same. (This is likely to change, because the borderlines +of the transclusions are a bit difficult to see.) +

+What to do if RASTER ERROR occurs +

+The writer of this document has been testing Nile for a while, but all the bugs are not yet fixed. +RASTER ERROR occurs frequently. Figure64 shows +the Nile Window after a bug. +

+To get back where you started from activate one of the GZZ-windows, press ESC +and move the green cursor and the blue cursor on the empty cells that you have +created for this purpose. (See ) Now you can return to the Nile window. (This +works often, NOT always.) +

+Quiting GZigZag +

+When you've had enough, press q. If you +want to continue working with the same space next time, use the same +cellscrollfile when starting. +

+List of keybindings +

+#include "../keybindings.wml" + + + + + + + + diff --git a/Documentation/UsersGuide/olympos.png b/Documentation/UsersGuide/olympos.png new file mode 100644 index 0000000000000000000000000000000000000000..9b8067eb45dcdac115c7ac4cabdc63a4a63429ed GIT binary patch literal 2554 zcmbuATToMX0>*XJq*^IJ zkti(3({>&ELQbyIAt$2eINm>Cj>w6O*$b0K$$k?f=yf-1e;s?2`S;;?KZmb*!3|yN zf=hssb_;PcyD_vQh4~eoRil=nQ{ukloJ=3M2Q|(3g-gM)ZftPK4ff^i} zl0{l!km#W!*9+JUK%cl9z29n|2PsrlEah+Y0yYjbt+KsxB|jfBgw)wHCd|$rnUC>K zHUb**S4qCX%91e|!{V+>dwc1ZKL==>Xbd|u5-o?{$DO=v(;C}eyg6{iPic=`v1}%U z2e2}Bp~F@wfE8N#@m$9fF4B8lU@ZMh|1x$8ie#=m`7ZQ_nFL#WaZ!mkCP9c_Ccjk6 zbs&Dj3i4+poEEp_s}_!1Yh;bJ_Jnt({RJ%m^+An35SF0m!y#D)xfK}d`BWB4r)021618^_>Hp2Irg7a&SKlKi#MQ*7vRF02O(JcRkZaiu zlXpP!51@f$Ow7=huu@N9tvA#KEnu*%R&pTV;nQyD6~BYaYfx@^uH#+fdUyf$Zq8#Sj2Ov&U?4r6!Y4P@Qa2b848&uzmW{q{O^8-(Q;Jjg13e{y?t zOuyJaz57ys!S^8Ka{0fdoM9Q8%Bidi-pQ-ba(5Jhz21soJ@CuiK_l=8nxIw%dMarG z*=1gi5LSd^tii3g6FjtbZ0|rzB0hX_FbwVfL|dH*EA~KwnVlZk&hq@zm_lr$VpJNL z8DJlN3gRn*8<5-qHnc72e#y7AW7r~+Qe7-_tlsyz2Gi7VeijY7dsItH#>>hW+>sw> z&D9Kz_nXZQ7lbf#r)ua-5r6qPZ+df~l$VlJ6CBC7IPF{Z(1FW!gtd~S~dXx~aZ za7B%K@C33lq%Y*-4E4%##0nCdK&M2qjP-oB6v%zqllt)tg(sfK2xrm4S#_uHDUO_* zZI16u#p;RgRXK5=H45$4mo$zEnCzO5&>^h{<3(Nszu``nH$DdYyraq)T4B4OrdJcN zV>E4%HJaWmRLM=iX7QaWO0-$duHP6@BjM&k2ReC7*cG*c}fqHJ=$|cul5pI!6WUd7zIn>ffQNl(7$W zRK{H%6Dc}J*)!sD@3idGOJzqp!n?7vdkoEMvU|{{SK9uTn88-Kto} zqq1H?-wQtZ%WCPV7atyMJ+J!etTzgmMfH{}SH)SmAZ=OwES||qQVfkX8AtZB9 zzj*YY9qD)IoOCQ!ZrfGKo@v_y9SgiAikdSoDSEg{=_Q~`Q+TE%%1b%M*@SEUmtvhc zG1Qh#>i###nx)ejXiCtCm;7N!RWSR)-Vq&Ge61PuNzdWyzAC<4HTiWNQo5;Fz+S1vJon_nr^+<0ALr3`+p{) zyp}3#ZIUNkP^4m2X-Utmhh|5Ck@({_VAk42&3wBJHO-kHWb4z(r|YsyECPEkN@)&h zXJ(_8v2Lv$ej{2M#Qy`f(A$ic8HXhAODP@CiZUgeP$5J!W?>8I+wn$SSoOpme*RMP zZDz$$Jv_2wI`@P$bd#q8no=pNyte&1;(8AI$-bCaA=_lKN67VleJe`>dyiNqvVZ=t z*Kh@69STQ@Vrvn6;bxT+%}B@ai}?}QWI%H1W}WU?!PKxE0jju);CNN6yKaK+udN(RQv7awM!fhVz0+s@q z2AyUL6BcN)4x?IuEVE{f_kkJgVkm21`9s*1j*7;+>8E)VCPr&huXv*BpFvoBf=aX< zLU)XJlwfO`w%@2+fXRV)r-VVH#IY>oOIRF@nB*KSYw5TLg^^}Wt1^1Q~qS49;E}azkS&Eec12ud->kJpAH`In>T0a z90Wn;`S0Cz7(r&>2r}c>FJ>YLG9EV>iy(;i!Tm>eKh!)x5X4rSZ)lJ=9!D@acPXK%~t=>7wj0P{gL#wgB z)Xl6}R?K@2JC9p-jFTr%8$R)`C3qH7lTVPIcK@>w32z~lf5f6(31XKP?jddf-?&Uo zwl;@&n;;8fSMBif>hFg~r^<>M_-c;8p?BiX_<@6XqX{|(j=t+-fq`5RZ#M9yq0OR; z^ftbioJH&h`i}ifrLr`;&>o zl7tN7g1Is}+SvdD)O{yP3f{U?FmiM@ebHbQ5Co1+E))sOMQf)EcH+6bD>GI#Kx~A= ztmocr+`~=%T%u&IXh?yo7o>Lkk3T|JBZ84P5QBl~RwFF(T3ZXRw~@*}O3P{4)Fb@^ z9#PrMSiFQgHSr_dL%hJQGO-adIyKP>?_3PfkP5}rX2oSVu}@J>i+w#kwa;gJ6f=n% zJQOBkaDi0ZJ7~mI_Q?N}`@V^;Bel?O-8)B#ZE`uLQlG(_^20>(^nbK7z+{#@B)&y) z13vilZ2Vt~awN(W(y$*!c0)%G;?tgS6hZ(jo`jG?7I!h5`346QbXAcmLB~b?*Xds7 z0c+nO>tQe7L0f^5hb|kQi&ekk4 z*F{}ed&Te4EAt~o?fVQo5BNqn?!B7Q^;NX3+l6=opSfyor%~*>NUbOBA|K_*Y0|-l zre+2ZxS=sL^i>#rY+?aMsikd1Wf?shl9bc%bmA{srrhlHIv|}0s8?dr?-DQp1$B%$ zRpb2ps`X_EbK|xahr-8c!;NLYNyik)6J5|43TlfDG>92@db1-xz*NI%b*K4pwfudf z52cm^J}0Z+HJaee)zKM737fWMS$fwcl;}Qb$H;Hf=muzUw&L6@m@0~JJ0jwlR@#c4 zW%fQ}H|I(*m3osz*xG}sJc+LWPjmn`W5n;{=T4dxXj;!D4s9Bq6vrA=c6BEBg#vLBS;UZ?`DVlE?Uw?x^`2 zyd!Au<|tfGUqL7&0-G(&m9PNAl280Dxb2GC`Gukq2KmKRB@r=qyS&WwZPlW(Bx??y zW+>s~3+pG}cb#`3=3?3v^{t!{tnpd|nGi#^_)QhYLOpbb^+fC*G+o3YH&A>HTiJ>- zY7Yw-JYTl((YDpZb%}`0sS#PfJTWcabYW==f9Wz~hH>tTzPoQ!DGTbbtu362dJ3S+ zePwX&QX^Q&v}aTfc?`9eJb|6RSQiGHhD5h5m$Bfv(!_}eu<-HL-aPHCvmMroi#eJ% z>>?TwQQ1-y#yre*mc8(#nEU$IXF7o_ClFFI+c4bTjtar*!kB_azjST5peupI)}O_N zRXNrPKo6p=^PVRtUrs!i6q%S-DEc@$7>i~Ec0B(s0*JDx{MnV(3b4uqLBL2@m9$y$ z2P|!Ryy$xqoJds%bgXo?QJBv8lKR1O(z^4N+|;=IzlYhXVJQr_DOC)L*&60?6{cm$ zDJ@>;^GB3vw(ZF)9}88h4lbh0MemB`OWH$lVX|O*Fuk)Q1qL+xeBDa-1@s56ND_{6 zbnJ1p-1|e3lWtM2oLHr$FjM$j8vOYoz%cTtHrNEp7>eJ7WT)2YLxFD!Sg5rwq@8!H z-FgPks@POoroR;bDEvC0U;PO%a+rs>MUPuPR8&5tHif!SFv;lz$I#W+tEu7AS^9H$ zRC4h?E(i(1%Pr<;(oLOgjpCgL5snFuI(M%<%U}Tnti(UXg|~Q}z`fwT z91hk+JY{NWz#H_(Haxg&$+$>%(XX8T|#T7~5KuEK2BN3 tER-|rR4QQP_g?}ra_6bb{|4Fp!L0xQ literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/osoite.png b/Documentation/UsersGuide/osoite.png new file mode 100644 index 0000000000000000000000000000000000000000..dc80cd0f7acdf52b5a4536ff4ca2956f4219f9c3 GIT binary patch literal 2860 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/rainy.png b/Documentation/UsersGuide/rainy.png new file mode 100644 index 0000000000000000000000000000000000000000..2feda4de959e72793691d58d3889ff343e43b2ee GIT binary patch literal 2278 zcmb_dX;4#X0(?4C>UyE8ju(fFgQy%49gUnRMMOo3Y z=#LOI=hWU^JC3Av7`m=z+z4Nl`6?H^Te4EJ=57)$^lA9eFl&d)mBq>Bd;T6B%5tQT zxJxlJe5m^MJfe_Blzxll$M8zVqYHp8-#YM;beItht39zC89i|&OgBi}+4xqZbF2ug zzJZpdF?|fk@=(?u0#*hSwYDvuCkjV1uIS#C%BoYD&Y08%IUCbaBUCt!Zvx}*m@j3_ z*F6?Sit(ZK$u-3SlCJ?~Y-eqwl0DtvrXo_SZB@ZYcqHme7qsWc3YL(lf_4I(X4470$OVgW+VG{>5*kAYrhp+&r8I%ZY0NnExL-a; zgUA+555;PBCTMMQ5Sh+Rb`#~$afgC)?fU{`aXJ>0Wro!@d&J+{O%9;{7an!!w{&q} z*#m%E*CVuGCiTDRNwdr?2Jomk@9Dh1EIR9l`b^eHk<52mcNis!zr$p74QU?}nXCrd zi6WpW?5-pQqV5Kf%0@+Qp4H!aC^x&>o|ywO0jpKyj`YgM;A@JtSR0%=+AZysv~F>m z#TS5S(YQn+39m=@0hc3Tai()0FVe|qs?Y)XwZtKYP~gzk)gQ`z4=#b#Nw%MTP9`=)EOkoD3Pn9)>ig3Rq7uk= znw1C;b2j^{MDE=KW9q?bW7gNKR-3GSKTCemi|}V~-RAHteHIYp`fpg(=pC@MW3o-# zxs!*O3apES)1O~~pyPQU=vAs+k(^+S(+8s10aiZt`CcqxD%Pni!;2+SE3bgo%7Mhc z$#hoG0j!l4BzSnt8SUMMn7*vD`m;0lqFQgRoNf3G2k4ugb@D=W08puw_W)mM>l^3R zhAfwKCt@PF=~;v|-paM^3rH4nB*-Xr!j4~s_`BB2041r*6I&AFG_BoGD`iyqjGQDJ zt#o3aZ;LHO+Mu%SLNx2wQ4rNXPj^e5T(eZ~mKgQ?mrC=K2quD@M7gCN*kPI=xF-eu z!REsnjhpy=&}%UdI4Z>&@kdWAnpU6u(Z72OBjc@8tEB%mmDKnmeZN!uys(@;m!Ymr z7@wRVKGz~pts#oDR@BNz3faBdWexU-<+{SUPW7Q2qUw&L`ipOGlNR*1C?`&%+(5@; z=BVr3{f-Npp5&4GgAr4SV*T!c?cWF&)^~vRu1cwQX1?_U(j=*FT++!;>dKdWr1IW_ zPgmN4{E(_WTiTR{xKG}bL9mX9sh(B@qWaePBj*PDVktht3cMAPDn5U`afhQae+HZ1`;wP!RUqIi!FO`DD`BG2t z+wuWsx9i?zAIRvUNBhEa8s*0y&lGY31wW4x!xY?dcdUm_zWqm7mpbFa@I+G`XZ}*d zbvA6b+|j-i*cJFQVB+IWknXrSRp{4MAZ&lxdnP2aJjQg)xEGx|KmS6uUnHT2NVB(4 zi67@93@{Zj()+aqSzFpGNPi<2!1K z6dpSE!f|y}Ecf6ytyf!Jz#u=u79v0I%yPkMs3uLkeH+suG|oikk;(|S8l44wa)f}H zO+l-z9CmKl<+Ai2Z-U=bkOxs6lQ|%<-xYZ-s7>{6IlvMt4v?B{BC6?_@n6hk+j`oc zUiZ^|Z+M<*5!dn?ywVe1fJCKQnRec#qBqb|U$xmNsiN^iQhW?5S@LV$Hdc)@Nkk@3!ZHgb;`X4Mao z6e>j(=%H&byY)$6{sAs_6g?2iO3fQih&k(rcscpYYd6ZTWASjR#M|N;Kz=)2?vr%% zQXd;XNrX7U1YK{{i=8k84Z(6LE6KuO*zq zPUlfVwjUQAUZ|rAO9oV)bpVjCgmtHmmZWFjz=jsf>`Vb9Z`aqABqn-aBU0PGM=&1y z;}~V-Vyhn3oO|ie;Ge-Hl+OI$zG*-0M1N?Sawt*1LA%!X{vDtDvf-g-5(RC!;QOD1 c&-OOE_U0BZ^8HgeU&OsZp}Q(}{^O^A16(@OZ2$lO literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/rastererror.png b/Documentation/UsersGuide/rastererror.png new file mode 100644 index 0000000000000000000000000000000000000000..75ad82efec58bb49f4287dc45527ab9d1ff6dcf2 GIT binary patch literal 2435 zcmbW2S5%V;0!HJo=qg4=MPZPlbVw*7AZ2h=nvp62Vq}7df9S|8QU#*u03t&PAru2c z(@4n}_=8~}AZ-mKp-6;;P=_K#0!T3sLfNzD>^|=~`#s*L`*goFHx~!!F~wsL2n33_ zVe1Zod`E>q4w1f-fLMaGfihwW$&Ge36jqK_&HGyc@;Fsc+nVWMhi|N>9oW+jv1DCS4&jA-?(B1yJ5>Y)a z9+w#J)u{cRqKZP|6MMWxcq~6&fI`p0&dGu>d?E)eGCU&KuE(){7NM7f-U)e%wSKEZ zkIwM3!d=5%1+4v@S0K#53!ga0+0k4lcQwolff9l+{clfw^3qL_0taHEQ_@w~A(S^B zgVm9ggYFnR(PA>TgikfB;d|ns!noI9k$m9u#79_xf-1@>6Kr+4AzJRQQVf)(;}Qmg zYyJ88$FY0|km`yMEmLdwO4yn6iW=z5!%B@R4|5Yw3ixsXe8W>`|J-1EMw>3Q$727m zE{HrXU`OA7roqVR&Mt#T7w^T-=5oF`STTR2Fm>3-DvlWAY_E>u3C z@n>`%=N+4oY?pQz@6;Jq!?rf^kV5At%GGpSGc!q#mWU7hcq>e!;&(kU_&x4Eb6`n^ zdP*M%VGMlE+q74;c8!@2lHBXMj*|4EW@HiR*jA8&#tqG2vd4dC)9WWMI@WA-)-;iY zc@^!bE0i>l&d^|35ypivJ)eSG#ca?jlcpze1RKwf{?1Z~hI79(w?tTPR}nI9$!?_U zC3tyVUVdw66>@M!?CS!Ep?l@4L#=!uJtTuCn~cYIS*GgU0M76=N3e*D#il8@mkHlmW{$GW3Kq~2I?!z=IZ zj*&P>AXos0@~=3}!5AOg`eM-Z7PwXTVtrDWM43e$KT-0~8Xa^ey|{b7YV|2MiIJ&i zD!S4qx)?mVs=)4h3mcV=AUfknNWsiXbj--O3P2qj@7s}r?cKka02~^_zaU;Db-}z>pf3zclxEt3Xe7Wn*?-!Or$A1(5M}By55sH<7PQHdSXo2zZ&Q8g-1JE~r?a@ClmaWRbez=LIr4`a5ShHIoKRK9fw zY2=`8Jmvdi$E5GxbhHcNa7W5De7+JiT3m54C0Ld-Lsq#;NX(Eht4tnG@lu zb2H2rt37(zD4>Y;06@POgbQfvO<&i82r?@Z)(WmGWz$QTY^Y}r(G@2~FipsHOgAk+ zeO>)eT~;14XYYbpb}}58?E3b&ef$k+XZHf`@#?FX&sRh3iO`iTtg`_)vCZm!;qY>4 zzKUYrP~~W2<~1hfB;?vti^j4q{is;mX98q|-LOAg5APiYnf!^6ld0u8!72y~mnfiu zy7ZDdp|F}UGf=3n+$z^8^N*O6&t1d}Q+?f6yJQXGJ4|(jIz|P*He78)pF0#&n{tHa zWnVuryoRmH+(got{X-H|`_@dM}|*FTlsW1MW@ zQ(^SLw6wxtYIcRij+^{zkq$CtNt0b5b24@?DmM=EJ2~)3R?8nk?ZRC6f71CxmHC0m z30wTsw3-wCi7I;2acWULJ|5;x5;i5T7JZWfDoA@*={g>TL zy4Y(|37d>_Ib9u`1N4$P#@HMzOWHz_uwVNFA@$L1~_Iup7LlzDi0jH$oJ#<9# z(8OZ0i@5_m!t#eI-;lyATRSBC)8^3`FR5ZTkEQr8iDd*gC(Bz@f;;6xd_dF{r!qp0 zt;k1Pk9Atu4H}nKlILuBP^@EcwZ^E1pzYqQ7RdcA*aB&lOC)TzP#7>+h$8-vdVmuj z_Z5n*GS5@?kU}1*f~a{{QXcMmfg^2A_h}TWCr?SSAi>t_EQ0QV7EFh8+koj?&I6YR zE8(fe7KqldR0FSvvYw^YwZ^IlEDU#V_t(*biMC#8oYEyt0c)3e9P-z(0uGFRE-=6} zmD>y>>717YmHU`vTtKp3RLwqn)C=^q(27`Nr{9=&%9e(Ey|TRAu^^{`Ua%uy^>|x9 zZnsf*-2c=1ZBH%L#cflCrWvAD6T!kh#yD-_@DFWwitm;rg&G-)ZvYkD_C%tEeT=3| z69uT^UNX1?YG{Vk0|?{7&9LMmU{M*(0&esCJ)xB$zLDHEbBk=Mo`qQJxmm3efLzEi znKO?>Xmz5?@1YSPnC|MkrSC799~dO}_H3vN{BDBig9mE=`$XFgP9wK#?r1Sn%1bgS zgjRQBd@Jf~ks-_EG+v+OZVE+re*QvshbmnYS>}4IVbwsWh3Xr%bLPA&PPV*XQon!W z9`G&oH!V$X7h7IjrZfRheBAphpnd7f^uDk04EnzY>T9YnyB+NCPru;*jSzM&wr{Wd GKK&QK9=I+5 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/rcfact1.png b/Documentation/UsersGuide/rcfact1.png new file mode 100644 index 0000000000000000000000000000000000000000..964d0d76fadef31d4f0e9a3c37e073d393d6ffa4 GIT binary patch literal 3539 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/rightmoved.png b/Documentation/UsersGuide/rightmoved.png new file mode 100644 index 0000000000000000000000000000000000000000..6fcaa3058dc9a4bb36349ee65527d87d2116aa09 GIT binary patch literal 24489 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/rotate.png b/Documentation/UsersGuide/rotate.png new file mode 100644 index 0000000000000000000000000000000000000000..81d6a0a1467ca700060f9987efa940bfcc7d1cc6 GIT binary patch literal 2564 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 OVm?TCziA)!%)bDmpM@0w literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/row.png b/Documentation/UsersGuide/row.png new file mode 100644 index 0000000000000000000000000000000000000000..d63ce8b5e0afd745296d419b1b30c1aaff6fdd5a GIT binary patch literal 1436 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 D@_q!Y literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/shinyhappy.png b/Documentation/UsersGuide/shinyhappy.png new file mode 100644 index 0000000000000000000000000000000000000000..b9c5ee5c20474b60a0195ca894bbff9472ce48fb GIT binary patch literal 2256 zcmb_eSx{367JcftmK&uFbR(n@6%`~h*s_^qT12!_V+%CxLSjQgqR6U*FyFGSa&bS;F6m~iGVr_P<{*<-(5@6SQ))4@f z9N53-`@lqvPMcX=yl?*bE@9chzl;0gT$9W!+qC)1q}Ol6c~(Z+M0(NXrrP-y`67`b zO~G~jh$dd*ZG^3gjg(=-ciG5TYO9$vJzOeawYf+TNckm^?;`2i$@gNVUG?47d`cdv zE*NTJ*QI~sE{374mIt-W9x$HD}8po7&c6N-6#rrJ8=@DSENPN*yxC=RO|QC zSuyK|dNvw9cWonV4JPD-i6`Wnv2i{U-DVnz-r;<{o!Dm5-^}K{rSJ_XWTtPx z{q5ZUv-I5NqRn6xbg;X4~>s)KU=`VSnks-$VMj? zjO6s(E*rTJiA%+O`TP(L%>0t*r#Y2J+g!YX|0n#{40NI=IOGB&?wVsPMIZ<7xp0fe zeDZwS6a75aIMYHpX%ruCd)^7T=$K_ogp}iq4%G?+o+96w;4Y{b7&(sBf9(CYwtl1jY#U_lEny=3ueCOs7MAEb_b zj^ORJCI?;NT2yHLUBBGOzw<-;QJ6V4JNzb#^5l{DF9xQzO7JwC_ZUrThQ(G#COeTC z*&`Wc;y&`^6GQMVXj%_Nd*hFJ!Z~&0ry&BT;jSuT<`SF$5mW03R-%OdgA`4=o(VO1 zgVPpMmCf?9Mb*(Gzwpsw#r2t%tfQ|(u`~Bd6{hQmL~2Y`ZNm@?IDS zi(SA}2VB7xIauiyoV3h0Y@%m)dMose9Q}(5nK|k<4!P&2bZz_UY=``GB{-=CuNFrp zBz&bw*fLg$GBWsml5?seFZ}(QL2I4E#dEZVdMXjuKshs8V09t)>MiM72Rs5&8Pe2Q z;dIq0OUKe>Gk+k04fqaAPPr6;#CZsQ{Ao$VzQ#ug2nQD#6+VECiadKK;93u5p*`*_ zZkoN4fvCa-pEqlrAnLu1lzgsoh+fEj%J-k+w6gNkb8siAL%<;3&(pGVWEmspM)UoA z-cmL%gPDYU*#UXs*)};-v4OtBai=4H{eX?wDhZTW7s+bo$V)7b+kzXQ2h@L!ySu*7 z-9>!CaSa<4C}}MNOto3qHNbOv-3;57+PZ5pqo8QYVFs0=jGItR)7l35e>75;gD}fe(-%;x z#E{n0ZRxu_7wi-UV19;&=2(Ybp=Gu58ghHaorV6!fyWz+UF9|LNp_3TW|`4 ziW(&TU;CtULJ1@V8a8WfZn&Z(tGZI(ZQy{DkWwy3s03kb496apt#y!C(N1}G?B+21 zIF@fl2jcIUw@Hu)g$Zw*81tI*(5NP*7 PTyekep*_OgCx81lWnRNa literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/shinyhappy2.png b/Documentation/UsersGuide/shinyhappy2.png new file mode 100644 index 0000000000000000000000000000000000000000..414f33d5da98f4d7f5b3e3632a2e0f8538edfdc1 GIT binary patch literal 2691 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 J67i28{s+DphG+l) literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/showingz.png b/Documentation/UsersGuide/showingz.png new file mode 100644 index 0000000000000000000000000000000000000000..9babe8dc58b0d95dd8fabd21e433dd4e1af314e7 GIT binary patch literal 7139 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 V>%J4sNB{r;Lp{?wmAVgK{u>gUCxZY0 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/start.png b/Documentation/UsersGuide/start.png new file mode 100644 index 0000000000000000000000000000000000000000..abebb27917f1d20c151793b0d6efeea76e91e886 GIT binary patch literal 1045 zcmajci&N4E0KoB|weqr=o~`TB)TLvVh|8^CrlpR~7dju84Ev>GF&+VGHxFsfS7n!H zHS>W#6;Nuk>~!igz5y%}wY&I^YxQg{6YegA^b-M2hBF~-@+-3b5y zXIyOL1pwG}5da)2ckKoMz$I;UKL7yxlE1=7-4yHq0I&lb6m5~K0butCE)t9XZfa>J zDVKNhqZ{9L&+UCt#EDuXM?Yxj()mm~&feI=N0xCz!*qV_KE}$Hp6+hM%sz}bnelS8 zvAOEA5F`hAX50S-M6R+)B%67juk&J$9NxMlq=*8UZK!wxa|)r_JMLgPZ@9Am;PKQd z+om5=FY1Ox$8?w@S#McHXYG?;&(Mh_B*X7QQPd^}{Ac3Kz3@*q*UO5dSTEB=;sTx=kA95;*zn!b3sfTR1>Swk4f);pQ-FqsRTR_ z-ymDfcO4540!Zv}w5v!uD1&Dq?7DXrcq5P#G@w$1*z|iON@ygU6 zrZ||oLV=N|# zD3E4mAAO)^T$7Lmre*Tv0oV{XkmJ>TZH5Y>&{=665^e!xQs(1fRSn7>(5vdQJe)7(+(##%*09OiK(PN6^oCOk*WHm$z#UWXq@`4nRJo85$Ig0>Woa|XAju5 z5NQI%yIhtfL^29jp&vMAQ4z(}I6c2KSS`am^_8bIV$JMFS(By%=Utj|xIES(Yi2Zz zT_UISJVnxpDWK0ikvF{OJ>Pc}et&b5nQ;H|dUM2wuNq%!Wy0iw}X~erKr=aaeR%JVSiHeiLaI(hr*{uZsP04*Ms}XReCvO)Li;WN literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/story.png b/Documentation/UsersGuide/story.png new file mode 100644 index 0000000000000000000000000000000000000000..f5bc5b4291742e2a3257c58367aed0fd01c1598b GIT binary patch literal 753 zcmeAS@N?(olHy`uVBq!ia0y~yV2WU1V4T3j%)r3FAN`G+fq{W1z$e7DasGb>28RC( z!v7fC~@zq0gq7&OTA~`@}7i?5&fw+MLsky!Gp4<<==% zPwdLPXJe2(vpQ_z&UD>hTjdtzckZ({$bKK$E;s+Xj%~={&D-W}wbehgt;Ncu?5vja z=Dw||UoU%Ye&)P+T9wTA*?P|othuz=Y~sA7?JL*p(%1d|yEf-qlF{mO{jP6<_vJeks5r`E}~d5=d~lAiXK zgSVo__nCcXe^wuT6RRbE)=9*Xt^IMw6yiPn-8MF#b$R>$iN- zEo#1+Px6I&Q*574lhZzXNpD{D$N&V0HiE%r>R>il2I&w6<~{_$(@@OGqMn=*N`i9%ek zU8K#^uUFHi^@}|ZGn)A{=)&y&y}|cx@jcpezpHH%$Q^%*>loX*`Y!&BRa*e!d%F6$ JtaD0e0su_cSK9yp literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/storytext.png b/Documentation/UsersGuide/storytext.png new file mode 100644 index 0000000000000000000000000000000000000000..bf31546c866ce82df0e1199948d8e07c643e1dba GIT binary patch literal 4760 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/structure2.png b/Documentation/UsersGuide/structure2.png new file mode 100644 index 0000000000000000000000000000000000000000..0a710037826092f6393d56949dfe614edac40067 GIT binary patch literal 2483 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 literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/suku.png b/Documentation/UsersGuide/suku.png new file mode 100644 index 0000000000000000000000000000000000000000..f6f82780fb71d6f98ded384c68dd352c73179e8d GIT binary patch literal 1811 zcmb`GYh03t0*7BK*R)c*Xr0VC^Kxp%7FjY=F)LGZYTmEtab=fzMM^?YPP6^AEXk!} zsZd+$)Tya4ffu3Dv_!>B=LKF_B9I}kCFPsG5a+iq=kxh+{vV$&&zI+a^<=Q$2J`La z003+V@IMv?047TSU~+%WY5)MR1=~pg0ANmj7vam1Gy?!&?B*B&z-R>+jle=jt(pNM7ARIx*oC2mN1?OB!-W@S$&50@a=SG>10ktreUrN7Pi?9p4V3G zr|_0J@JNu#6XyT^X$|~_083wJ@v(-t*WupJYOvYM91Rd%#bZ=#Zw`6Q;>0huj}&3% z2ChuG^27n#CeO=FY{`!GHpdmuWl~J!<;=8NtiyY68Np>EzUj8rrPy;G@2NufJ~D{* z{t^EbDOJ_@p{`ALo!pUk+-3cdE}}7`UX?_Drt&A>erXK-fQsSXYKq`&mFr>`fu9P& zNGBI}N(hCC3G6X1vCa!tm0?AF&_kKTRu_ca1ZD^D6NIxjs0r@VgA{1c1&uOT$v!-X z;xUn=s{Io7hcC|dfh{n<9P}{rnC=J%JL4Kv4`V5G+}ZpJEY;;*J-x#HuCq+C(4r&p zG%cQ@s_{cJt5*z6zOH3)7lIT03Rj}G{*?5YTJa|EOPH%D@ql0GQY5EmQDN+fRq!EG zB$|CRZjUEd@o5ga5kIi|o6BZ_9)p~obC6CpD$@vEOpvK!W^d?Dcrim70pHGP3W!V0 z5t|nnQe%V+SCy-AgDGNbv+X)9`SC~g-jRfQamrq%=0c44?Z}vUcn>y-&vg9qALN%= zI1G8Y!lx0A)gEWxrOFg}x76L++a)@sbJ1wmz&xL&Hgx)4;3`u}`J#Q45T*OjeJ!i@ z4NFrX+&Y9FlATfpt}5XwN~mG5j-UrSme@`*^;NFDV3%vR*M8&)&)S2g*6lPwzOSd2 zN>rhsL!eVR*68mg%2nv=9P@0g)%&t}tMy~~l)WVYoRtUNHmHbv&QzcuOl5zze>FgLG zjKoELPO2&*)sWfN$(8D4K_Ms*=fa^x=&?iAKwG8y&R@T_ zMtt|fnxl`r@JM7hi4(Io{6f;QWM?uG83ymMRX072`vu}j6}<NbQc+ zimTjW_0Ass_pcaQj(=|+Cnnm!x`XC&e$TD}ZFcio3BbvOJ37jLg|Al`SC_bX VU&bfK=>LWRzQM;@j{NJ#{{ZEwwyppG literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/testi.png b/Documentation/UsersGuide/testi.png new file mode 100644 index 0000000000000000000000000000000000000000..3053d5255d6a7ab1f50ec706299ec61d64fc7d59 GIT binary patch literal 2395 zcmbW2ZCFx=0>_Ve%i8j#S<_`orOWMFx@Bgi$n9-ro6*)9%}r2IQAuev0Y${@#kDdk zDrO9*yynVHID(29KNO!57e}x#B3k!~s1WxX*LH_3_^4`F;I=`F;5R&g|b8 z@A=lsw*Ua}OxUyQ3jlCK0l@9wi`@YLcy-Kv6aaw8{hxigTd%1G0Kj$kkqZD^fRD=s zSlb|%w7TKWWoAZ_%jG(E`q+-`Ti2}iKgoCbSQfinkNP@ptO0<U!p^lPta(@W6fj@?Wgx_xhQ_$MFY;FQS&PoHaSLA2o@7#(LN{!{xgH zv2DgRMiOV97m2{2{3>+Hdjz@Blc#rjvKU%9K~eKKPeqoDhE3GY6{qKU%dU+I$U9CE z?hsdBj^5|(JzK?KjAreP5bF(ISUS*BrgA{A$un+ zIoUiy#)DNNg}fZc+6zzrHYKaG*`nZ3MOo%W>jjDs8)NWqr9}KJ7JgI-ofI5Z(ZDjF zMF_;);a@ohsu6Q4HrStD0!#OINOL3Q+>fMXn;O+4f;mh!p zT*2wVKIc-56Z5Cv+w-<8>u1)p3UifpReM=$2#wI{dO;o8Q@oAmFB@e#-Z!$k36s2F|xv5eJ;niV7u#$pbZ<(7ERY*cPm1 ze8M}g?r+Gf@#kIU46Rl6zJhz7#2xCFEq9zRj7DUsEb6V~(cl=EvZY-ep%)>pGtb6I zbD>Ev6J5AyIU9lhG>ZON|4H~F9$5?JAzvXfhWCV*j|BI?p1=Zf5+X7R$T{Yj8M1Ap z25N|XVLFEoA~#9|UqfjTvEt8@lV9T5a?8Lu+#M-L!{WJ~7};O{A{o_J$V@mW_z|xj znZJ$bFuKbJV;Y`ko6;S+rkqrh5YZlGJ44~-1C&{b<)u+Lw!*mtnQGGD~CbWPmsIdp7b4_ zX9e*?)GX{+DQNt5+bTs(D|LtKKH*lP4OVv+f3T!Bs`&nqHjS-|>iTd93~ecONbvb%=D~saa*mebTg7=_y%qF;K0!x#huNeZ3$Cwbh~L) zGo|JLtx2azMCVpa!3XFOLm=w{K32b!SBm&?1CDYsE>2brg4pQ6YsipqhKF{A;g{p& ztAVfA!LwNn14F`e4{bhrI4H*9S19uaWy*g~tB7nrL9=JEY)mxsxj+*5I>}huW$LO>-92Gm zz?)V_+T!URS}K~ho#pVLyAHCaYSRSwXFtRl`&;EFiOvA|5O~6Tq(&Um*(rItZtw$) zIX|F&8b>jgnBB3Z{Hf+t*)4Bp@YRk@y9uxBVA6EUenb8Ev`)GSyX;qJ)lQz}yP@at z+YaSNSfdld=oJQ2esL&v#R<*1^;|+&m7_JqsJCYmqBoSuaekKyMlmiU&v981aC*!}bjIuj2Q4Oy}ti z&<Ettj){cXcw8-s8Y z`fP;|a%!`$_bqLXrbg?6MkI$23xnp^c@X?d8qyrsZCrOR9J%&2mkxt;fTKD2s2X~RQ)lhB)?uJWRPgN6~{V1 zo(|J)L?h8LV}F-(5g#$si^9HxR{N3k1&o65-s463w7G2b7?pI_L_ag-!`awpfKvCf z%7&xFbQbydipcvr2YNyT4ZchDhgmAlKK;jpzof8X+GwFXiCArG$}n0KBpr1FSC{(* zX^DWZ(w^ndWXWtk_NKeE@)C$Vvz5){B_SMkX`sUU{3wn01D4cZ8@h2~bGEEIPX-k@ zgND}>hCMGpqhImDIarF;hgYrsfRvR+uHKhDL?$a{-U96w< zQ91E>-bO3!o4N5(A-%}AS@CwW!Xim@5WN`M*)_Y_+Lv@P@^;I=$^x68bvp04P71i9ikb zCdaMvi;*}JWJ#de4SP98o?WN;4xLngKwLG!@v?xdv&1&34`%zWUvi?Qh`RyJt+z|n z(XMJ6f7@A%{_4++Q+IBts7X@8{2?70Q7I*q}vxhhSa4d1^OKd+|NZ0aReM zX`55q-W*-)n2ahw;Cy4);nH0-3&h+1pHmM>=-YeaSEAqVy-S+W2gUqKZVuAZs7_`Z zOcF!KvFDCmux@dTJy|Kz2ilzZeOsL=pSMXD^9U<>Ylos7bN$*fjZ%VRM{|W#Akg$8-uDTs5rT+nu12PE! literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/ug.wml b/Documentation/UsersGuide/ug.wml new file mode 100644 index 0000000..056b6ed --- /dev/null +++ b/Documentation/UsersGuide/ug.wml @@ -0,0 +1,400 @@ + + + + + + GZigZag User's Guide +#include '../wmlinc/article.wml' + + +{: [[s/(?)\b(d\.+\w+)/\1<\/code>/g]] +

GZigZag User's Guide

+
$Id: ug.wml,v 1.6 2000/09/12 17:12:13 tjl Exp $
+ + Tuomas Lukka
+ lukka@iki.fi
+ Dept. of Mathematical Information Technology
+ University of Jyväskylä +
+
+ + + +

+This is the first attempt at an user's guide for GZigZag. It is not yet +complete and not a good tutorial but we will try to work on it. Patches +are gladly accepted! +This is work-in-progress: if there are any unclear parts, feel +free to ask me to clarify things. + + + +

Introduction

+ +

+GZigZag is a free implementation of Ted Nelson's ZigZag structure. +The ZigZag structure is a revolutionary new way of storing information +in a computer, in that it provides a clear, extensible structure +that can be orthogonally laid over existing information. + +

+This document attempts to help users to get started with GZigZag. +We start at the point where the user has gotten the program to start; +to get to that point, read the other documentation, including +the README files. +Note that this document does not attempt to cover designing sensible +structures: the "Gentle Introduction" document is for that purpose. +Here we only explain how to use the GZigZag implementation of the structure. + +

+GZigZag is a moving target: we will try our best to keep this document +up to date but sometimes it will simply be forgotten and be out +of date. Please notify +us if this happens. + +

The save model

+ +

+GZigZag currently stores data in directories, in which there is +one file per dimension and one or two extra files for the contents of the +cells. + +

+In the new, cached and explicit model, the data is loaded at startup +and stored in memory until it is explicitly saved. +Pressing ctrl-S saves the changes. +And indeed, in GZigZag, it is only the changes that are saved: +like CVS, GZigZag stores all the previous saved versions implicitly +as well (XXX Because of timestamp problems, not usable yet). + +

Viewing and moving around

+ +
+ The initial display of two windows next to each other. To fit them + in this document, they have been horizontally resized but otherwise + the view is exactly what you should get when starting GZigZag. +
+ +

+The first figure shows the two windows next to each other that show +up when starting GZigZag on an empty space. +There are two cursors, the green and the blue cursor, which are +seen on the same cell, the home cell. From the home cell downwards +(poswards on d.2) is the system list, which contains +metainformation about the structure as well as keybindings, which +we shall return to later. + +

+Let's move the blue cursor that defines the center of the +right-hand window down three steps. There are three different +ways to achieve this: either clicking on the "AllFlobViews" cell in the +right-hand window or by pressing the arrow down key thrice, +or (probably the most counterintuitive at first), pressing the +comma (,) key thrice. +This moves the view to the one shown in the next figure. +If your machine is fast enough, it should animate between each step +in order to better show how the cells move around. + +

+ The right-hand window, after moving the cursor down three step. + Both cursors are shown in both views, but + moving the blue cursor has moved the center of the right-side view + with it. +
+ +

+The last way is actually the recommended way since it allows you to +keep your hands on the main area of the keyboard at all times: mouse input +is not needed in GZigZag. +The direction keys for the X and Y directions are i, j, l and ',' +for the right-hand view and +e, s, f and c for the left-hand view. If you look at the keyboard, you'll +see that they are arranged in two diamond patterns on the keyboard, one +for the left and one for the right hand to use. + +

+If you look at the upper left-hand corner of the windows, you'll see +that X and Y are not the only dimensions here: there is also a third +dimension, Z, on which d.3 is shown by default. +A place in the default structure where d.3 is used can be found +by moving two steps right and one down from "AllFlobViews". +The depth cell is connected to other cells poswards on d.3. +The keys to move the right-hand view along the Z axis are k for poswards +and K (shift-k) for negwards. + +

+ A place where the third dimension shown is used, as discussed in + the text. +
+ +

+There are various different views to the structure, press 'v' or +shift-V to cycle through them in either window. + +

+Before going on, you should train yourself to use these keys to move around +in the structure. The direction keys will be used in many places later +on in this guide, since they also form a vital part of the commands. + + +

Editing the structure

+ +This section does not give all the possible operations but +tries to give a subset that will be sufficient. Marking is not discussed. + +

Creating new cells

+ +

+ We shall start from the home cell. + + Press 'n' (for "New cell") and 'l' (the direction key + discussed above) and a new cell is created left of the + blue cursor: + + The same would work for the other view, you just need to + use the direction keys for the green cursor after the "n" + command. + For practice, move to the new cell (press 'l') and + press 'n' 'l', 'n' 'j', 'n' 'i' and 'n' ',' to create new cells on all + sides of the new cells. Note that when creating the new cell + leftwards, it is inserted between the first new cell and the + home cell: + + +

Entering text

+ +

+ Now, press Tab and type in some text: + + Tab moved you to the text editing mode which is pretty + much like familiar text entry mode in other systems: + the arrow keys move the insertion cursor and typing a character + inserts it. + Press Tab again to move out of text edit mode, and + the insertion cursor vanishes. + (NOTE: one planned feature is to have the background + change when in the edit mode - these pictures were taken + when this did not yet happen). + +

+ Try putting more text into the other cells. + +

Connecting and disconnecting cells

+ +

+ Now we get to the most important part of ZigZag: making + actual structures. + There are actually several different ways of connecting + cells but we shall only cover one because there's no + time to write this user's guide completely yet. + +

+ The way to connect two cells is to move the cursor of the + left-hand view (green) and the right-hand view (blue) + on the two cells, press '/' (slash) and a direction + to connect the two cells in. + Connect will fail if either of the two cells is connected + in that direction already, except if one of them is alone + in that dimension, in which case it is inserted next to + the other one. + + + +

+ In this situation, pressing '/' ',' or, equivalently, + '/' 'e' results in + + +

Hopping

+ +

+ Hopping is a structural operation where cells are reorganized + along a rank. + It's easiest to figure out if you try it: press 'h' and a + direction key. + +

Alpha-shear

+ +

+ Another structural operation that can be very useful is + the alpha-shear, which changes a connection from the current cell + to another one in the same rank. + +

+ It is used by typing 'a' and two directions: first the connection + and then the direction into which the connection is to be moved. + +

Cell exchange

+ +

+ One more editing operation which helps a lot in making the structure + work the way you want it to. Press '%' (percent) to exchange + the connections of the two accursed cells in the visible X and Y + dimensions. + No other connections (Z or invisible) are touched. + +

Cloning

+ +

+ Cloning is an important structural operation in GZigZag, + as explained in the Gentle Introduction. + Basically, a clone of a cell is a cell poswards from that + cell on d.clone, but with the special property that their + contents are implied to be the same. Cloning is visually + shown by GZigZag by coloring the clones yellow and the original + light yellow. + A clone of a cell is made by placing the right or left cursor + on the cell and pressing 't' or shift-'t', respectively, and + a direction in which to place the clone. + + Pressing shift-T 'l' creates a clone of the left (green) cursor + and places it right of the right-side (blue) cursor: + + + +

The system list

+ +

+In this section, we explain briefly what the system list is, and +what you can do with it. + +

+Basically, the system list contains information for the user interface +of GZigZag, i.e. the types of views, keybindings etc. It is possible to +configure GZigZag to look like something completely different +but you must act carefully: it's fairly easy to accomplish something like +the following: +

+ Hmm, I want to rebind the keys completely. So let's delete the + previous binding list (click) and then I'll start making the + new bindings list (click.. click.... click....) oops, it's not + responding! Right, I just deleted the keybindings list so of + course it will not do anything when I press a key. Duh! +
+

+So remember that any changes to the system list are immediately +reflected in the behaviour of the user interface. At some point +we will probably create a mechanism for making delayed changes that you +can commit all at once but this is not yet in place. + +

+The system list starts at the home cell of the space and continues on +d.system, but for your convenience those cells you will most likely want to +use are cloned to a d.2 rank starting from the home cell. The d.2 rank +is freely modifiable but changing the text in any of the system list cells, +or breaking the d.system rank can lead to dire consequences and you probably +shouldn't do that. At a later date, the system list will probably be locked +by default. + +

+The cells on the system list simply enumerate the functions: the +actual cells that describe whatever are connected to the system list +cells on d.1. + +

Dimension list

+ +

+ The DimLists system list cell has connected to it on d.1 + a cyclical rank on d.2, the dimension list. + This list contains the names of dimensions that the views + will cycle through when you press X, Y, Z (possibly with + shift/alt). + +

+ Adding a dimension simply involves creating a new cell and + typing the name into that cell. Likewise, deleting a cell + will delete the dimension from the list (but not currently the + connections along that dimension). + NOTE: don't rotate to an empty cell: this will possibly + cause problems: at the very least, a raster error. + +

+ The dimension cursors of the different views + are a variety of pink shades. + These dimension selectors of the different views are actually + generic cursors so it would be possible to have different + dimension lists for each X, Y and Z of each view but at the moment + it's not possible to repoint them to a different list except by + trickery. We will probably provide a mechanism for this. + +

Views

+ +

+ The views are defined on three different cells in the system list: + Views, + AllViews and + CellViews. + These cells have different functions. + +

+ The windows cycle through different views by moving in the + list below Views, much like the dimensions are + cycled on the list below DimLists. + The cells below Views describe one particular + view. + +

+ The cells below Views are actually clones of + cells below AllViews that actually give those + views' parameters. For instance, the Vanishing and StretchVanishing + rasters use the same Java code but have different parameters + in the structure below AllViews. + +

+ The structure below AllViews is simple: + it is a list of the clonable cells (which name the views, but + the name is just decoration for the user: the real information + is in the structural operation of cloning), which are + connected on d.1 to the structure that actually defines the view. + +

+ The defining cells are structure along the ZOb structure, + explained better elsewhere (XXX). + +

+ Not all views in AllViews are by default cloned to the + main + Views + list for two reasons: first, there are too many views to just cycle + through, and second: some are not yet very stable or useful. + Experimentation with them is encouraged, though. + + +

+ CellViews + is similar to + Views and + AllViews + in that it also contains a list of cellviews, i.e. how to render + one cell. + + This is because currently there are not enough different cellviews + that having a separate list of more possibilities is not necessary. + + +

Bindings

+ +

Actions

+ + +

The keystrokes.

+ +This is a list of (almost) all the currently available keystrokes +in the default bindings. As explained above, it is simple to modify the +bindings. + +#include '../keybindings.wml' + +:} + + + diff --git a/Documentation/UsersGuide/wallstreet.png b/Documentation/UsersGuide/wallstreet.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e3b892f865686e74ec299da092f04942b88169 GIT binary patch literal 2630 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 Q0001WPw4L2FQP8~8%I&NasU7T literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/widthstr.png b/Documentation/UsersGuide/widthstr.png new file mode 100644 index 0000000000000000000000000000000000000000..f3e5aaf07599b2dfa45818a441836e0431f76a1b GIT binary patch literal 1590 zcmb7@TTl~s6vo#&lvYt%J0l2{$SBZONkoL`gf&8?a)%<4VufhgkOFd(ngB_FBFZQf z1%y-sruA+Su)9&z1X8(#L71C{x!qHO`|#{HDODDxGK3vZ zFh?hcMTnBHGau5AoME%nR5^~ezqObMqB$-zrwT1FIa{?eOW{vb5cc=F=2Tchj2-Uo zr@aqswEe*X^XrYz96M+Jw7WDQdO3y=M){HWo?!ABus-i#$WLw}12Y7Y3hQ!G%Ej6y zP6WwuT8G0Wd@}GTK6sxgD>W2b+-uxN{5pF;S8z;0RFCG&cDb7SiGg60HqlrT%>x|qTbrlfbC^A_72_9T zBx>`s=o_mU)Vk1{IEWS4dJW17Y@f))Qh55jDS+1}1@YYu zIcK%~64cmgt?ZKp+-ib!K zgVmMM{ycW8dbE&L%!_#sl&l6NRpE&*hJ9;1<)Wqs7(LUqr0?Tj9wB@Mi#IT;rV63} z-)3nPmcprXBi;2Jwiii_Iht6Dk9*aOM$~Xay5(t`YH@(_>8I1K0XgXh*}s^njK6ltny3x@J61ERYgh z1jbdE;f$>NI)^qn;_$K?q3DJd1ZFoP=H-JMGx@ds^zK@Q#4 zDY@L9=|OJ^h8=WAn6RbNZ6pdcv|WrMoSS9z_8@^y(VkrdFB7HnXlYK$Z(m@20o(ML z=*>Fmwys!W{Or1ivODeS-?WSI zhZ0y(xrc7on2#UgnuVW(6mH5&mv>F2lGRwf=<16MxgXI&-~O_0py4MZ=LcQy_$C4E zl>5kjUODVU?l;`g)B4tqhbTO?8N-0!Bi2S$1w1LM@4g5t>Fi0a#-S-yzfyiA+0DvW zFwGYd8TQi6rf9|T9JhH5NMI9;$caHODVO3P%=R6)*>?EiWF{=%oB6WZCEBE!k|H_l z1op$X8+yE4$)Nz#g`WEx_X?Q#sk0Xn!I!p_rQU=k*3~nd6vPxNtSMtjs`9xF16wXh zCx3)bkIj@N2a(fVS-_w%-J2)mtcmeh@^$&#n@Yg&Bf>GGJr}D%X9ytE@PF5@RJF8S z4whs{BPWKq{8J%3uwHFCb9fRJdyb&yRG!Oj4V3}5rbqsl68=x+dMtIcqBpyGL{L(i zQUf`Fjy^7fYX>=Xw7IFPwOPJ>^yWXRW1@-Ru!c*|`zm`&>uO0^n?v4e{<}?2jnhoo WP*3k!`S|jMp}%j)j#{66d4B;^ST|Py literal 0 HcmV?d00001 diff --git a/Documentation/UsersGuide/wrongconn.png b/Documentation/UsersGuide/wrongconn.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca0c232f06e61f121ee50b4de120514fdca66c5 GIT binary patch literal 2600 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 literal 0 HcmV?d00001 diff --git a/Documentation/diagrams/Makefile b/Documentation/diagrams/Makefile new file mode 100644 index 0000000..36fd595 --- /dev/null +++ b/Documentation/diagrams/Makefile @@ -0,0 +1,5 @@ +all: + @echo "go away" + exit 1 + +include ../lib.mk diff --git a/Documentation/diagrams/ZZCanvas.dia b/Documentation/diagrams/ZZCanvas.dia new file mode 100644 index 0000000000000000000000000000000000000000..a9752b2fe8bbf1aaf1c289059c79b23aec0cda3c GIT binary patch literal 770 zcmV+d1O5CTiwFP!000001MQe!Z`v>rz~A{4QFvtzp`<`ts5YJ^ZR*SR(ie0ICb)I% z$aY}7?6c1y;a@^11k!C4NJNS`?ss>&J3IIA_$#2s3=2s(>zg)enva9p!{3NZ2bmG!O}vOIj9-Nwt_Jzh}Y6pP)ZOtQrKV+ z;J)dC_v#BCv9Xy*rE(spTo^N;eX~AUeoQM>W9{fUpgV*Ri>%rpOT6o1412~c^A1IhBbY6>ebS<00B5=&u$ zMQYiXO|cs@B8f|J8p^FI=I#sjR9c@uzkf468AA$Enwvh=Gz~KDn@`Q%;?4#_YtqkC zX3IO|gsCJ94(d7$2i-cGP!t8C2;jO|{X&}$%%^zGh!OX88{PD7TMfI3dgXAK;$Y-) z!SXHZay~5~b23)bykD#2?4q{z&g9cAUvq;OpFJ$KZsV5Hi{Ym0GNbw AHUIzs literal 0 HcmV?d00001 diff --git a/Documentation/diagrams/cursoring.dia b/Documentation/diagrams/cursoring.dia new file mode 100644 index 0000000000000000000000000000000000000000..601d6ddcdff4a02168ed11ab07e159768eb55bef GIT binary patch literal 1282 zcmV+d1^xOTiwFP!000001MOQ~Z=*OAeb28z^kr9K3^w1*w4FJ40`hYd zUJtMs8z3DUK#UEL6gN2+QqV-UK^B~+jAj*%6dQItP7%=*LghI}@bRtRCQ|Yj`hQE) z;t&U_+mExRcLr9s8dJW6P3Z#@bpQNpbS;Um^l#Sw1aA%ovX9K%DtyBm?d@#w=?ESeAk zyr9`KWsfiDVwE6s?1C5s22iIzrT`4}>OlGrLvLdLb7ud461LTfoJE=my%q_D#B8Gfk39q9af<+jLu#BkAt>|%$51!NRDlyXcZd*#2uhk@5`yXDtF>rZu3GtN}rhAJ`NBzZL&GgZZDJzzG5am~zyO0D}Cmf^por z4U}MEVh|V9U{wAe?A;;!?<3D5&cy#`T?9mG7l6f+0t{3D*B}n^CkZ%_1pEao8dDL2 z0{od|tV06a;oAU?;UhBcCV=fKj5!doUDpA}X8sY+vKyAgr3bI`Ym5Q`A|%S2z1Y>n zhc&8vf)RuFTD17?=M!xOk)X~FU|o~Eto^jzQxy+p^8iDm(bL46H#FXC4-o^0<8C|I zu3C(6)VTwIa}}OHa=dl<)nNr4bIYE&|3|=`CIO@dD>NW=oum>R6^};z0)G{c@ zkGlHxv)>r4AL>&uzs0DKEYF$v5K*z@zrV|57>~Xf-j28_4L*q^^>9QuI4vP6NhMGw zjjTyHR4A6B2|GY8HV7`S&VeRcBr(y$QS{ImY!g9@Nf3DWq3N=a@W+{3cBvVU)nq0AR9Zf3-kHwHYUe0b4QAlmc;X;E{x_k~P<}URxX7IhN s^*GwVvx#MnT90c7?0euC>kT-jx-NgmaXs7np~v;?KclEQuR%5d03O<6i2wiq literal 0 HcmV?d00001 diff --git a/Documentation/index.html b/Documentation/index.html new file mode 100644 index 0000000..c4b881d --- /dev/null +++ b/Documentation/index.html @@ -0,0 +1,130 @@ + + + + GZigZag documentation + + + +

GZigZag documentation

+
$Id: index.html,v 1.4.4.1 2002/03/07 19:56:13 ajk Exp $
+ +

+ Most documents referred to from this page are incomplete. So be + warned. If there is something that you'd need urgently, please + contact the developers at <zzdev@xanadu.net>. +

+ +

+ Note that all HTML documents are available in two flavours: one + that works if your browser's CSS support, if existing, is not + too buggy (such as Mozilla, Netscape Navigator 2 or 3, or + Konqueror); and another meant for users of Netscape Navigator 4, + which has bugs that make the normal version illegible when the + stylesheet support is on. Choose your format wisely. +

+ +

User's documentation

+ + +

+ New users are encouraged to start with Gentle Introduction to Ted + Nelson's ZigZag structure (NS4-compatible + version). It introduces the reader to the ZigZag universe + in a general way without touching the aspects of actually using + it in GZigZag. The background information given by the Gentle + Introduction will be invaluable to a GZigZag user. +

+ +

+ The article GZigZag - A Platform for + Cybertext Experiments (NS4-compatible version), written + for Cybertext Yearbook edited by Markku Eskelinen & Raine + Koskimaa, is an excellent introduction to the potentials of + GZigZag. +

+ +

+ The GZigZag User's Guide (NS4-compatible version) + introduces the reader to the actual using of the GZigZag system. + This is what tells you how you create new cells and connect + cells and so on. +

+ +

+ There is also a GZigZag glossary + (NS4-compatible version) that + contains short definitions of key GZigZag terms. +

+ +

+ The The nile (nile is a literate editor) + applitude (NS4-compatible version) + article and Nile User's Guide + (NS4-compatible version) document + a new experimental way of writing text. +

+ +

Developer's documentation

+ + + + diff --git a/Documentation/keybindings.wml b/Documentation/keybindings.wml new file mode 100644 index 0000000..b880fb1 --- /dev/null +++ b/Documentation/keybindings.wml @@ -0,0 +1,182 @@ + +

Default bindings for the orthogonal rasters

+ +
$Id: keybindings.wml,v 1.4 2001/03/02 07:13:37 ajk Exp $
+ +

+These are still being discussed and are not yet frozen. Note that there is a +panic button: if there is no binding for ESC, it invokes undo. + + + Key(s) + Binding + Ctrl-S + Commit the current changes to disk. + ijl,kK + Up-left-right-down-Z+-Z- in view 1. + esfcdD + Up-left-right-down-Z+-Z- in view 0. + n dir + Create a new cell in given direction + b dir + Break a connection in given direction + h dir + Hop the accursed cell in the given direction. + Hopping means simply switching the places of + the accursed and the indicated cells in that + rank, no other ranks are affected by + the operation. + xyz + Show next dimension on list on X/Y/Z in view 1 + Alt-xyz + Show previous dimension on list on + X/Y/Z in view 1 + XYZ + Show next dimension on list on X/Y/Z in view 0 + Alt-Shift-XYZ + Show previous dimension on list + on X/Y/Z in view 0 + / dir + Connect the center cells of the right and left views + in the given direction, if no connections will be + broken by this. + ~ + Exchange the cursor positions of the two views (no + other view parameters are changed). + Delete + Delete the center cell of view 1 and move the cursor. + Cursor move tries following directions in order: + X-, X+, Y-, Y+, Z-, Z+ and finally goes to home cell. + + m + Mark or unmark the cell in view 1 + Enter + Execute cell in view 0, with the cell in view 1 + as parameter + v + Change raster in view 1. + V + Change raster in view 0. + Alt-v + Change raster in view 1 backwards. + Alt-V + Change raster in view 0 backwards. + Home + Go home: move view 1 cursor to homecell. + Esc + Move both views to home and reset dimensions to first + three dimensions on first dimlist. + 0123456789 + Insert the given number into the number insert buffer + for cell IDs. + g + Move view 1 to cell whose ID number was in buffer + G + Move view 0 to cell whose ID number was in buffer + Backspace + Remove one number from the number insert buffer + + t dir + Clone the view 1 cursor to given direction (may be + in either view). + T dir + Clone the view 0 cursor to given direction (may be + in either view). + + % + Exchange the X and Y connections of the two + accursed cells with each other. + + o + Go to original (rootclone, cell from which accursed + cell was cloned) in view 1. + O + Go to original (rootclone, cell from which accursed + cell was cloned) in view 0. + + End dir + Move to te end of the rank in the given direction. + + < + Set the cursor of the left-hand-view to the cell the + right-hand view is pointing to. + > + Set the cursor of the right-hand-view to the cell the + left-hand view is pointing to. + + - dir + Connect the current view1 cursor into marked cells + in given direction. Direction must be in view 1. + + Alt-c + Switch into "curseling" (cursor selection) mode (see + below). + + a dir dir + Monochug: change one connection. See above. + + +

Text edit mode

+ + + Key(s) + Binding + Esc or Tab + Switch off text edit mode + Delete + Delete one character after cursor + Backspace + Delete one character before cursor + Left, Right + Move the cursor within the current cell + Home + Move the cursor to the beginning of the text in + the current cell + End + Move the cursor to the end of the text in + the current cell + Ctrl-A + Move the cursor to the beginning of the current + line in the text of the current cell + Ctrl-E + Move the cursor to the end of the current line + in the text of the current cell + Enter + Insert a line separator in the text before the cursor + any key producing a printable character + Insert the character in the text before the cursor + + + + +

Curseling (Cursor selection)

+ +

+As an intermediate for multiple cursors, there is a key binding mode for +"curseling:" cursor selection. In the standard keybindings, Alt-c is used +to go into this mode, which by default supports the following key bindings: + + + Key(s) + Binding + Tab, Spacebar, Alt-c or Esc + Select this cursor, quit curseling mode. + Left, Right, jl + Select next/last cursor in system cursor list + in view 1. + Up, Down, i, + Select next/last cursor positioned on the same cell + in view 1. + sfec + Like Left/Right/Up/Down, operating on view 0. + + +

+Note that you can create four additional cursors through executing the +CreateCursors command, found in the action list, by centering the left view +on it and hitting Enter. + + + diff --git a/Documentation/lib.mk b/Documentation/lib.mk new file mode 100644 index 0000000..0c9c395 --- /dev/null +++ b/Documentation/lib.mk @@ -0,0 +1,33 @@ + +%.html : %.wml + wml -I ../wmlinc $< -o $@ + +%-ns4.html : %.wml + wml -I ../wmlinc -Dmode=ns4 $< -o $@ + +%.ps: %.dia + dia -e $@ $< + +%.png: %.ps + # gs -q -sDEVICE=ppmraw -sOutputFile=expdia.pnm -r288 -dNOPAUSE -dBATCH $< + gs -q -sDEVICE=ppmraw -sOutputFile=expdia.pnm -r144 -dNOPAUSE -dBATCH $< + pnmcrop expdia.pnm | pnmpad -white -l20 -r20 -t20 -b20 >expdiac.pnm + mogrify -antialias -geometry '20%' expdiac.pnm + # mogrify -antialias -geometry '10%' expdiac.pnm + pnmtopng expdiac.pnm >$@ + rm expdia* + +%.tex : %.ptex + gpic -t <$< >$@.new + mv $@.new $@ + +%.dvi : %.tex + latex $* + latex $* + latex $* + +%.ps : %.dvi + dvips -o $@ $< + +clean : + rm -f *.html diff --git a/Documentation/misc/ADDRESSING b/Documentation/misc/ADDRESSING new file mode 100644 index 0000000..8d930c4 --- /dev/null +++ b/Documentation/misc/ADDRESSING @@ -0,0 +1,26 @@ +A XML pointer-like scheme for addressing elements in a ZZ space. + +Neighbours of a cell + + (cell).n(d.2,+).n(d.1,-) + +Headcell of a cell + + (cell).negcell(d.2).poscell(d.1) + +Searching for an intersection of two ranks (the cell itself won't count +so you can repeat it and get all crossings) + + (cell).intersect(d.2,+, (cell), d.1,-) + +this is useful e.g. for searching clones: + + (cell).intersect(d.1,+, Color, d.clone, +).n(d.2,+) + +to find the next cell giving the color through a clone. + +XXX textual searching? + +There should be a way to detect changes not only to cells but also +expressions like this. Implementing settings would suddenly be a lot +easier. diff --git a/Documentation/misc/Curseling b/Documentation/misc/Curseling new file mode 100644 index 0000000..8bb9339 --- /dev/null +++ b/Documentation/misc/Curseling @@ -0,0 +1,46 @@ +How to use the cursel feature (as of 00-08-04) + +"Cursel" means "cursor selection." There is now a mode where you can choose +between different cursors for a view. Here are the instructions as to how. + +In normal mode: +Alt-C -- switches to cursel mode. I like to reconfigure this to spacebar -- + much faster. Note that the view's background now shows the color of + its current cursor -- useful when there are multiple cursors on the + same cell. +Esc -- now re-attaches the standard cursors to the views before it moves + them to the home cell. When you're lost, hit Esc. + +In cursel mode: +Left/Right arrow (or sf or jl): choose between cursors on the system list. +Up/Down arrow (or ec or i,): choose between cursors on the same cell as the + current cursor. +Tab or Spacebar or Esc: Select this cursor, quit cursel mode. + +To get four additional cursors: +With the left view, go to "CreateCursors" on the Action list. Hit Enter. +Note that you can apply this multiple times, but it'll give you multiple +cursors of the same color. + +To bind the two views together: +Go into cursel mode. Hit Left, Right, s, f, j, or l until both views have the +same background (and thus, cursor) color. Quit cursel mode. + +To bind a view to a "magic cursor:" +Go to the first entry on the FlobRaster list. Make sure at least one of your +views is shows this raster. Go into cursel mode. Hit Up/Down (or e/c if you +use the left view) until the background of your view gets white: this means you +have attached the view to a cursor without an associated color. Raster cursors +don't have associated colors (at the time I'm writing this). Now quit cursel +mode. Move the cursor up and down and watch what happens. (Easiest way to get +back to normal from here is to hit Esc.) + +To show very clearly how the cursing system in ZZ works: +Create the four additional cursors (see above). Edit the dimension list so that +d.cursor is on it. Cursel the golden cursor, go to the FlobRaster cell on the +system list, and go to the rightmost cell. Now cursel the violet cursor and go +to the FlobRaster cell. Make sure at least one of your views is set to the +standard vanishing raster (whose cell is between your two cursors now). Rotate +the view so that d.1 is on the X- and d.cursor on the Y-axis. Now play around +with the violet and the golden cursor, and show how the connections on d.cursor +change. \ No newline at end of file diff --git a/Documentation/misc/RENDERING b/Documentation/misc/RENDERING new file mode 100644 index 0000000..cae3b1f --- /dev/null +++ b/Documentation/misc/RENDERING @@ -0,0 +1,37 @@ + Requirements for rendering of ZZ spaces. +$Id: RENDERING,v 1.1 2000/05/16 14:57:58 tjl Exp $ + +This document is intended to start the design of the final ZZCanvas-style +thing. + +Basics: + + - placing arbitrary (extensible) graphics objects on the canvas + - either depth or reverse order to simplify rastering code: cells + rastered first should be on top, not bottom and breadth-first bottom-up + is annoyingly difficult + - getting some identifier of an object at given coordinates for e.g. + mouse clicks. IMPORTANT: could this be done by rerendering to avoid + memorizing too much? OpenGL / FreeWRL-style instead of widget-style? + TRADEOFF: + normal render = const1 * N, click = const2 * N + widget-style: const1 larger, const2 maybe smaller. + opengl-style: const1 smaller, const2 maybe larger + - for java.awt.Graphics, widget-style is somewhat necessary anyway + to get depth. However, memory consumption might go down. + - the BIG advantage of widget-style comes when there's lots of stuff + and everything does not move or change: then we can use the widget + objects as caches of stuff of interest from the structure, and set + the necessary tripwires (ZZObs) to change those objects if the structure + changes. For the textcloud stuff where most items stay still much + of the time, this would be advantageous. + + +More interesting: + + - access by other components to the raster: getting various mouse click + places + - rendering XOR-cursors for text when moving the cursor, to show where + an insert would occur + - same when dragging another piece of text. + diff --git a/Documentation/misc/TORESOLVE b/Documentation/misc/TORESOLVE new file mode 100644 index 0000000..ad21821 --- /dev/null +++ b/Documentation/misc/TORESOLVE @@ -0,0 +1,8 @@ +Questions to resolve with Ted + +- master dimension list + +- should we have a mechanism in the views to step through +tree structures so that left -> right takes us back where we were? +In essence, storing in the structure the information about where +this client was (d.prevcursor)? diff --git a/Documentation/misc/billow b/Documentation/misc/billow new file mode 100644 index 0000000..f9ad6b0 --- /dev/null +++ b/Documentation/misc/billow @@ -0,0 +1,20 @@ +Date: Mon, 22 Nov 1999 02:12:38 +0900 +From: Ted Nelson +To: "Tuomas J. Lukka" +Cc: ted@xanadu.net, marlene@xanadu.net, xanni@xanadu.net, eharter@din.or.jp +Subject: :zx,virt: "Mouse control for billowing (Was: Re2: I take it you mean... Re: Billowing + +I suggest: + up and down move the position of the billow, + right and left affect its size, + right and left with right button down enlarges and reduces + the font sizes in the billow, + while left button at any time marks the text, as usual. + +Motto: Key assignments are the most changeable aspects-- + they hardly affect the virtuality. Mapping of function that + seems consistent with usual functions is a constraint. + +Best, Ted + +.... [message being replied to clipped by Tjl] diff --git a/Documentation/misc/byrokratiadoku b/Documentation/misc/byrokratiadoku new file mode 100644 index 0000000..d0971e8 --- /dev/null +++ b/Documentation/misc/byrokratiadoku @@ -0,0 +1,169 @@ +\documentclass[a4paper,12pt]{artikel3} +\usepackage[T1]{fontenc} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage[latin1]{inputenc} +\usepackage[finnish]{babel} +\usepackage{times} +%\def\zigzag{ZigZag} +%\def\zigzag{{\fontfamily{yinit}\fontencoding{U}\fontsize{5}{7pt}\selectfont Z} +%{\huge i}{\fontfamily{yinit}\fontencoding{U}\fontsize{5}{7pt}\selectfont G} +%{\huge}{\fontfamily{cmr}\fontencoding{OMS}\fontsize{30}{30pt}\selectfont Z} +%{\large$\displaystyle \alpha$\Huge\bf\selectfont$\gamma$}} +%\def\gzigzag{{\it \Huge G}\zigzag} +\def\zigzag{ZigZag} +\def\gzigzag{G\zigzag} +\def\url#1{\texttt{#1}} +\pagestyle{empty} +\begin{document} +{\hfill{}{\Huge Projektisuunnitelma}\hfill{}} +\vspace{1.2cm} + +\gzigzag"-projekti tutkii ja soveltaa käytäntöön nykyistä edistyneempiä +tiedonhallintamenetelmiä käyttäen pohjana Ted Nelsonin \zigzag"- ja +Xanadu"-malleja. Lähtökohtana on, että nykyiset +tiedonhallintamenetelmät ovat riittämättömiä vastaamaan tulevaisuuden +haasteisiin. Ryhmän olennaisia tutkimusalueita ovat käyttöliittymät ja +informaation varastointi hyperrakenteisiin, sekä näiden tutkimusten +tulosten soveltaminen käytäntöön. + +Suurten tietomäärien hallinta on nykyjärjestelmillä hyvin hankalaa, +koska tiedostojärjestelmässä ainut tiedostojen välinen tieto on +hakemistorakenne. Hakemistorakenne on hierarkia, eikä siksi sovellu +kuin yksinkertaiseen kategorioihin jakamiseen. HTML:ssä hakemistorakenteen +puutteita on korjattu linkeillä, jotka on varastoitu tiedoston sisälle. +Nämä linkit ovat yksisuuntaisia ja rikkoutuvat helposti. + +Tietokannat ovat paljon tiedostojärjestelmiä edistyneempi tapa hallita +tietoa. Ne ovat kuitenkin kovin jäykkiä järjestelmiä: tietokanta +suunnitellaan yleensä yksittäisen sovelluksen käyttöön, eikä sovellu +yleisen tiedon varastointiin; tietokantajärjestelmät eivät tarjoa sen +enempää mahdollisuuksia tietokantojen väliseen linkitykseen kuin +tiedostojärjestelmät; ja tietokantoihin on harvoin pääsyä ulkopuolelta +--- usein ainoastaan WWW-käyttöliittymä on saatavilla. Tietokantojen +merkittävimmät edut tiedostojärjestelmiin nähden ovat mahdollisuudet +tiedon tehokkaaseen hakuun ja tietojen välisten suhteiden tallennukseen, +mutta ne eivät ole tarpeeksi joustavia yleiseen tiedonhallintaan. + +Projektin päätavoitteena on luoda \gzigzag"-ohjelmisto, jonka +päälle voidaan helposti rakentaa tiedon esitys"-, haku"- ja +käyttöominaisuuksiltaan nykyistä parempia ohjelmia. Ohjelmiston pohjana +on \zigzag"-rakenne, joka koostuu soluista ja eri ulottuvuuksia pitkin +tehdyistä kytkennöistä. Rakenteessa tieto on soluissa, joista +kukin sisältää paljon pienemmän osan tiedosta kuin nykyiset tiedostot; +yksi solu sisältää suunnilleen saman verran tietoa kuin +taulukkolaskennan solu. +%Toisin kuin taulukkolaskennassa, kyseessä ei ole kaksiulotteinen soluhila +%vaan moniulotteinen soluavaruus, jossa sama informaatio voi olla kytkettynä +%eri dokumentteihin eri ulottuvuuksia pitkin. +Toisin kuin taulukkolaskennassa, solut on kytketty toisiinsa moniulotteisessa, +joustavassa rakenteessa, jossa jokainen solu voi olla kytkettynä mihin tahansa +soluihin. Rakenteen ulottuvuuksilla voi olla eri merkityksiä, +kuten esimerkiksi ''pöytäkirjan 3141S sisältö'', ''viittaus'', +''tarkennus asiasta kiinnostuneille'', tai ''hakemistorakenne''. +Ulottuvuuksilla ei myöskään ole samanlaisia rajoituksia kuin reaalimaailmassa: +kuljettaessa ensin ylös ja sitten oikealle voidaan päätyä eri paikkaan kuin +kuljettaessa ensin oikealle ja sitten ylös. + +Kytkentöjen kaksisuuntaisuus on eräs \zigzag"-rakenteen tärkeimmistä +ominaisuuksista. WWW:ssä, jossa on käytössä yksisuuntaiset linkit, ei ole +mahdollista esimerkiksi lisätä omia reunahuomautuksia sivuihin, tai selata +niitä sivuja, jotka viittaavat tai lainaavat jonkin kappaleen dokumentista. +\zigzag"-järjestelmässä nämä asiat ovat helppoja, ja oheisinformaation +mahdollistaman suodatuksen avulla vältetään myös asian hukkuminen erilaisten +reunahuomautusten ja tarkennusten viidakkoon. + +\gzigzag"-ohjelmistoa kehitettäessä on tarkoitus tutkia erilaisten visuaalisten +menetelmien etuja, kun niitä käytetään koko järjestelmän laajuisesti. +Ryhmä pyrkii parantamaan sovellusten käyttöliittymiä jättämällä pois +perinteisen ''ikkunat, valikot ja painonapit'' "-mallin: tieto on +esitettävä kontekstissaan, ei pilkottuna laatikoihin, joilla ei ole +minkäänlaisia keskinäisiä yhteyksiä. Menetelmistä ehkä tärkein onkin +Focus+Context, jonka pääideana on tuoda käyttäjää kullakin +ajanhetkellä kiinnostava tieto (Focus) mahdollsimman korostetusti +esille, ja siihen liittyvät asiat (Context) sen mukaan, miten tärkeitä +ne ovat fokuksen kannalta. Focus+Contextiin liittyy läheisesti +animaatio: kun käyttäjä liikkuu tietorakenteessa, on hyvin tärkeää +näyttää, miten uusi tieto liittyy edelliseen, ja paras tapa näyttää se +on animointi. + +Ryhmä kirjoittaa tutkimusten tuloksista artikkeleja kansainvälisiin +konferensseihin ja julkaisuihin, mm. UIST, HICSS ja HT01. Tällä hetkellä on +tekeillä artikkelit Focus+Contextin soveltamisesta viestiketjuihin +ja suureen joukkoon tekstidokumentteja, sekä artikkeli, jossa esitellään +\zigzag"-malli yleisellä tasolla. + +%\gzigzag"-ohjelmiston lisenssi on GNU Lesser General Public License, +%sama kuin Linuxin GNU GPL, paitsi että se antaa enemmän mahdollisuuksia +%\gzigzag in käyttöön kaupallisten järjestelmien pohjana. Tällä hetkellä +%toteutus on prototyyppiasteella, ja sen avulla voi kokeilla \zigzag"-rakenteen +%soveltuvuutta erilaisiin tehtäviin. + +\gzigzag"-ohjelmiston kehitys on julkista, ja ohjelmistoa levitetään +menestyineiden Linuxin ja Apachen tavoin vapaalla lisenssillä (GNU LGPL). Tällä +hetkellä toteutus on prototyyppiasteella, ja on saatavissa verkosta +osoitteesta \url{http://www.gzigzag.org/}. + +Vuoden 2001 loppuun on asetettu seuraavat tavoitteet: +\begin{itemize} +\item{Viesti-, kalenteri-, yms. järjestelmän prototyyppi (Sonera).} +\item{Uudenlaisen tekstinkäsittelyohjelman (Nile) prototyyppi. Nile eroaa + nykyisistä ohjelmista mm. siten, että tekstiä voidaan lainata + niin, että lainauksen vieressä näkyy dokumentti, josta lainaus + on. Dokumenttiin liittyvät asiat, kuten kuvat, kelluvat tekstin + vieressä, jolloin pitkäänkin tekstiin liittyvä kuva pysyy koko + ajan näkyvissä, vaikka tekstiä selaa eteenpäin. Versiointi takaa + sen, että vanhoja versioita pääsee aina lukemaan, ja + lainauslinkit (transkluusiot) sen, että intertekstuaaliset + yhteydet voidaan esittää käyttäjälle ymmärrettävällä tavalla.} +\end{itemize} +Vuoden 2002 loppuun mennessä on tarkoitus toteuttaa \gzigzag"-ohjelmisto +solukielillä (''bootstrap''). Tämä vaatii ensin tehtävään soveltuvien +solukielten kehittämisen, ja on eräs tärkeimmistä kehitystyön +vaiheista. Solukieliin siirtyminen mahdollistaa selkeän +\zigzag"-rakennetta käsittelevän ohjelmakoodin nopean kirjoittamisen, +ja siksi tämä vaihe on hyvin olennainen sekä tutkimustyön että +\gzigzag"-ohjelmiston kehityksen kannalta. +\newpage +Projektista vastaa FT Tuomas J. Lukka. Tehtävät on jaettu projektin +työntekijöille seuraavasti: + +\begin{tabular}{ll} +Katariina Ervasti & Tutkimus humanistisista näkökohdista, dokumentointi ja + popularisointi. \\ +Tuukka Hastrup & \zigzag in teoria. \\ +Antti-Juhani Kaijanaho & Soluavaruuksien versionhallinta, tietoverkot, + solukielet ja \zigzag in teoria.\\ +Tuomas Lukka & Projektin johto ja kokonaisuuden hallinta. \\ +Tero Mäyränen & \zigzag in käyttö multimediasovelluksissa ja solukielet. \\ +Vesa Parkkinen & \zigzag in hyödyntäminen kämmenmikroissa ja multimedia. \\ +Rauli Ruohonen & Solukielet, \zigzag in teoria ja kämmenmikrot. \\ +Kimmo Wideroos & Tietokoneavusteinen oppiminen ja prosessikirjoitus.\\ +\end{tabular} + +Ryhmä tekee yhteistyötä professori Ted Nelsonin (Keion yliopisto, Japani; +Xanadu, Inc.) ja saksalaisen opiskelijan Benjamin Fallensteinin +kanssa. Professori Nelson yhdessä tohtori Lukan kanssa kehittää +\zigzag"- ja Xanadu"-malleja eteenpäin, ja Fallenstein on mukana +\gzigzag"- ohjelmiston kehitystyössä. + +\gzigzag ia ja sen perusajatuksia voidaan periaatteessa hyödyntää minkä tahansa +loppukäyttäjälle suunnatun ohjelmiston tuottamisessa, mutta erityisen hyvin +se soveltuu tietoverkoissa toimiviin järjestelmiin ja integroituihin +järjestelmiin. + +Projektiin liittyviä riskejä ovat: +\begin{itemize} +\item{\zigzag in hyödyntämisen jääminen vähäiseksi, koska se eroaa niin paljon + nykyisistä järjestelmistä, että siihen siirtymisen kynnys voi olla + korkea.} +\item{Suljettujen tiedon tallennusmenetelmien yleistyminen voi luoda + esteitä \zigzag in yleistymiselle, sillä ne rajoittavat mahdollisuutta + tehdä \gzigzag ista yhteensopiva muiden järjestelmien kanssa. + Suljettuja tallennusmenetelmiä käyttävien ohjelmien tekemiä + tiedostoja ei voi lukea muilla ohjelmilla.} +\item{Toteutuksen vaikeus.} +\item{Avainhenkilöiden lähteminen projektista.} +\end{itemize} + +\end{document} diff --git a/Documentation/misc/keys b/Documentation/misc/keys new file mode 100644 index 0000000..e9a9582 --- /dev/null +++ b/Documentation/misc/keys @@ -0,0 +1,80 @@ +Initial ZigZag key bindings +--------------------------- +Enter Execute cell at cursor 0 +Del Delete cell at cursor 1 +0-9 Enter digit into numeric buffer +BS Backspace digit in numeric buffer + +< Import rank from text editor in specified direction +> Export rank in specified direction to text editor + +s, S Move cursor 0 negwards in X dimension +f, F Move cursor 0 poswards in X dimension +e, E Move cursor 0 negwards in Y dimension +c, C Move cursor 0 poswards in Y dimension +d Move cursor 0 negwards in Z dimension +D Move cursor 0 poswards in Z dimension + +j, J, Left Make link or move cursor 1 negwards in X dimension +l, L, Right Make link or move cursor 1 poswards in X dimension +i, I, Up Make link or move cursor 1 negwards in Y dimension +",", Down Make link or move cursor 1 poswards in Y dimension +k, PgUp Make link or move cursor 1 negwards in Z dimension +K, PgDn Make link or move cursor 1 poswards in Z dimension + +G Move cursor 0 to cell number +g, Home Move cursor 1 to cell number + +Alt-s Hop cell at cursor 0 negwards in X dimension +Alt-f Hop cell at cursor 0 poswards in X dimension +Alt-e Hop cell at cursor 0 negwards in Y dimension +Alt-c Hop cell at cursor 0 poswards in Y dimension +Alt-j Hop cell at cursor 1 negwards in X dimension +Alt-l Hop cell at cursor 1 poswards in X dimension +Alt-i Hop cell at cursor 1 negwards in Y dimension +Alt-"," Hop cell at cursor 1 poswards in Y dimension + +Control-D, Alt-d/D Edit cell at cursor 0 +Control-K, Alt-k/K Edit cell at cursor 1 + +b Break link in specified direction +h Hop cell in specified direction + +Control-L Redraw all windows + +m Mark/unmark cell at cursor 0 +M Mark/unmark cell at cursor 1 +Alt-m Rotate selection groups +Alt-M Save selection group and start a new one + +n New cell in specified direction and edit +N, Ins New cell in specified direction + +Q Toggle cursor 0 cell view +q Toggle cursor 1 cell view + +R Reset dimensions for cursor 0 +r Reset dimensions for cursor 1 + +T Create clone of cell at cursor 0 +t Create clone of cell at cursor 1 + +V Toggle cursor 0 refresh raster +v Toggle cursor 1 refresh raster + +Control-V, Alt-v/V Display Zigzag version +Control-X Exit Zigzag + +X Rotate cursor 0 X axis dimension +x Rotate cursor 1 X axis dimension +Y Rotate cursor 0 Y axis dimension +y Rotate cursor 1 Y axis dimension +Z Rotate cursor 0 Z axis dimension +z Rotate cursor 1 Z axis dimension + +Alt-X Flip cursor 0 X axis dimension +Alt-x Flip cursor 1 X axis dimension +Alt-Y Flip cursor 0 Y axis dimension +Alt-y Flip cursor 1 Y axis dimension +Alt-Z Flip cursor 0 Z axis dimension +Alt-z Flip cursor 1 Z axis dimension diff --git a/Documentation/misc/textcloud b/Documentation/misc/textcloud new file mode 100644 index 0000000..07f1a3e --- /dev/null +++ b/Documentation/misc/textcloud @@ -0,0 +1,250 @@ +Some parts of an email exchange between Tjl and Ted, edited. +(If these were real transclusions, you could jump from here to see the whole email +exchange. Wouldn't that be just so nice...) + +---------------------------------------------------------------------------- + +>Any progress on the textitems stuff? That is one priority since +>that would represent an entirely different view of the ZZ structure +>(vstreams), with interesting connectivity and applications. And I want +>to use that to write my next pieces of ZZ documentation! + +OKAY. Here's what I think you asked me for. +- keyboard commands to step around among flying items +- how to glue them together +- how to separate one item into two + +IN ADDITION, I think we want +- how to make an item bigger or smaller + +- - - - - - - - - - +Let's call this Item Cloud mode. + +I ASSUME the items can be borderless, just flying items of text on a + shared background (so in principle two identical items could cover + one another textually). +NOTE THAT since my PC Java won't accept arrow keys, I have to + have the letter alternatives esfc ijl, ESFC IJL> and sometimes dD kK. + So when I say "arrow" I mean one of those. +I AM HOPING that Java can receive keystrokes-up-and-down (raw). + +The following are keyboard suggestions to try. They should all be + reconfigurable. The trouble, of course, is making them reconfigurable + as sequences rather than as individual strokes. + +SELECTING A RIGHT-HAND ITEM: +- Select by mouse +OR (once one item is selected) +- use ijl; arrow keys to select among them. I suggest that up and down + should refer to items within epsilon vertically of the original item, + and the same horizontally-- in other words, when using arrow keys, + stay roughly near the one you're currently near. This we'll have to + fiddle with parametrically. (It's also possible to select the next item + within unseen vertical and horizontal channels-- an alt. approach.) +OR +- use the space bar to select next item IN ORDER OF CREATION. + +SELECTING A LEFT-HAND ITEM: +- Select by mouse +OR +- use esfc keys to select among items. + +TO MOVE AN ITEM +- ctrl-esfc or ctrl-ijl, +TO CEMENT LEFT AND RIGHT ITEMS +- capital S or E appends the left to the right +- capital F or C prepends to left to the right +- capital I or J appends the right to the left +- capital L or < prepends the right to the left +(Note that these are like the connection functions in Perl ZZ.) + +TO CUT +I suggest space-!-space. +Or \. (We'd go into a Special Mode if you actually want the character-- + NOT \\ for most people. +Ctrl-enter would be great, if we could do it in raw mode. + +TO ENLARGE the right-hand-item a little (its typeface) ++ +TO SHRINK the right-hand item a little +- + +---------------------------------------------------------------------------- + +>> TO MOVE AN ITEM +>> - ctrl-esfc or ctrl-ijl, +> +>And with mouse? For moving things around, the mouse is pretty good. + +Oh, of course. Sorry I forgot to mention. + +>Also, how to use the mouse to select - mouses have up to 3 buttons +>and use of shift/ctrl at the same time. + +Right. Sorry. +1. As you said, click and type. I presume you're typing on a big 2D +space, and that Items aren't distinct till you end one? + +2. Ah, we haven't talked about how an item ends... I guess with same + "sever" mechanism, no?) + +3. Move by left-mouse (to seize). + +The question is-- when should the mouse seize an item, when should + the mouse start a new item? +-- especially since it may not be exactly clear whether we are on top of + an item, since there are no borders +-- and as the area gets crowded, you want to be able to start an item in + the middle of another item. + + +^Õ ^Õ ^Õ ^Õ ^Õ ^Õ ^Õ ^Õ ^Õ ^Õ ^Õ +But why not use the other mouse buttons for Billowing? + That could combine it nicely. +---------------------------------------------------------------------------- + +>> SELECTING A LEFT-HAND ITEM: +>> - Select by mouse +>> OR +>> - use esfc keys to select among items. +> +>So here you can't use the space? Or use ctrl-space or shift-space? +>It would be nice to have the same ops for both sides. + +ZOWIE! SHIFT-SPACE! LOVE IT! That's perfect. + Never thought of spacebar with a control key. Or at least + not in the last five or ten years ... + +---------------------------------------------------------------------------- + +>But how do I append one item on the right to another item on the right. +>Example: in the left cloud, I've typed a number of ideas I want to put +>into a text, and in the right cloud, I'm working on the actual text. +>So most operations would only touch the right-hand cloud. + +and also + +>> SELECTING A LEFT-HAND ITEM: +>> - Select by mouse +>> OR +>> - use esfc keys to select among items. +> +>So here you can't use the space? Or use ctrl-space or shift-space? +>It would be nice to have the same ops for both sides. + +Here we have great examples of WOOOOPS communication. I didn't + notice that you mentioned left and right clouds. I thought we were dealing + with only one cloud. + +So anyhow shift-space would be the most consistent. + +---------------------------------------------------------------------------- + +>mouses have up to 3 buttons +>and use of shift/ctrl at the same time. + +I would say that since 90% of the mice in the world have 2 buttons-- +- Mac with 1 button is what, 5%? +- Linunix is even fewer, I think +- W98 and W2000, with 3-button mice are rare +W95 is still way the majority-- and they are an important market. + +Thus we DESIGN for 2-button mouse, leave the middle one explicitly + to be programmable. + +In other words, the third button can only be for shortcuts + and extra options. + +---------------------------------------------------------------------------- +>> TO CEMENT LEFT AND RIGHT ITEMS +>> - capital S or E appends the left to the right +>> - capital F or C prepends to left to the right +>> - capital I or J appends the right to the left +>> - capital L or < prepends the right to the left +>> (Note that these are like the connection functions in Perl ZZ.) +> +>But how do I append one item on the right to another item on the right. +>Example: in the left cloud, I've typed a number of ideas I want to put +>into a text, and in the right cloud, I'm working on the actual text. +>So most operations would only touch the right-hand cloud. + +Since when I wrote my part of the above I didn't realize you were + talking about left and right CLOUDS, I assumed that each hand + would be wandering in the one and only cloud. This is more + exciting. + +(There's a poem in English that begins, "I wandered lonely as a cloud..." + But not otherwise relevant.) + +Now how to choose? +Heh heh ... +Okay, Tuomas, it's time for MORE CURSORS! + +This is where we need the operations +- cursor fork + (Specifying which hand, assuming you're using two.) + This creates a new cursor under the chosen hand, pointing at the + same place, switches to it. +- next-cursor-step + (Specifying which hand, assuming you're using two.) + This switches under the chosen hand to the next cursor in the cycle. +- cursor kill + (Specifying which hand, assuming you're using two.) + This annihilates the cursor under the chosen hand, + prob. goes *back* to previous cursor in the cycle. + +For some wild reason I think qaz (right) QAZ (left) would be + the correct respective keys for these functions. They're in a row + and out of the way. So-- +qQ - cursor fork +aA - next-cursor-step +zZ - cursor kill + +So let's say you have two cursors. Left is in the left cloud, + right is in the right cloud. You want to start cementing items + on the right. + +Do +q- makes a new cursor (and new color) on the right; +AA- switches the left hand to that cursor (since presumably + the list is left-right-new-(loop back to left) +aa- switches right hand back to right cursor + +Now you can move and cement items as I suggested above. + +When you want to go back to 2-cloud operation, you can + either kill the third cursor or switch from it. + +ChrzT +---------------------------------------------------------------------------- +u sez + +>> 1. As you said, click and type. I presume you're typing on a big 2D +>> space, and that Items aren't distinct till you end one? +> +>Sorry, the last sentence again? + +Sorry. +You're in mid-item. Item is on big virtual sheet of paper but began + somewhere other than at top of paper. Item becomes distinct + when you end it somehow, presumably beginning another item. + +>> 2. Ah, we haven't talked about how an item ends... I guess with same +>> "sever" mechanism, no?) +> +>Escape? + +Could do. In the ASCII charworld, backslash also good. + +Anyway, if it's one character, it's easily reconfigured. + However, I'd also like an alphanumeric sequence, ideally + (just my preference), +sp-!-sp + and that means some deeper recognizer, eh? + + + + + + + diff --git a/Documentation/wmlinc/art.css b/Documentation/wmlinc/art.css new file mode 100644 index 0000000..12f8ed4 --- /dev/null +++ b/Documentation/wmlinc/art.css @@ -0,0 +1,26 @@ + body { color: black; background: white; + margin-left: 15%; margin-right: 10%; + text-align: left; + font-size: medium; + } + h1 { margin-left: -15%;} + h2 { margin-left: -15%; margin-top: 2.0em; margin-bottom: 0.5em; } + h3 { margin-left: -7%; margin-top: 0.75em; margin-bottom: 0.5em; } + h4,h5 { margin-left: -0%; margin-top: 0.5em; margin-bottom: 0.25em; } + h1, h2, h3, h4, h5, p, ul { font-family: sans-serif; } + h1, h2, h3, h4, h5 { font-weight: bold; } + h1 { font-size: xx-large; } + h2 { font-size: xx-large; } + h3 { font-size: x-large; } + h4 { font-size: large; } + h5 { font-size: medium; } + dt { font-weight: bold; } + dfn { font-weight: bold; } + code { font-family: monospace; } + .figure { float: right; padding: 1em; padding-bottom: 0em; + border: 1pt solid black; margin-left: 1.5em; } + .figureimg { text-align: center; } + .abstract { width: 60%; text-align: center; } + .algorithm { font-family: serif; background: #00E0E0; margin-left: 1cm;} + span.red { color: red; background: white;} + span.green { color: green; background: white; } diff --git a/Documentation/wmlinc/article.wml b/Documentation/wmlinc/article.wml new file mode 100644 index 0000000..47a69a6 --- /dev/null +++ b/Documentation/wmlinc/article.wml @@ -0,0 +1,7 @@ +#include "common.wml" +#use wml::std::toc style=ol type=11111 + + + diff --git a/Documentation/wmlinc/catart.wml b/Documentation/wmlinc/catart.wml new file mode 100644 index 0000000..f75ec47 --- /dev/null +++ b/Documentation/wmlinc/catart.wml @@ -0,0 +1,56 @@ +#include "common.wml" + + + {#TITLE#: %body :##}

%body

+ +<: + @sectcounter = (0,0,0,0,0); + sub sectcounter_reset { + my $level = $_[0]; + while ($level <= $#sectcounter) { + $sectcounter[$level++] = 0; + } + } + sub sectnum { + my $level = $_[0]; + my $rv = ""; + while ($level >= 0) { + $rv = "$sectcounter[$level--]." . $rv; + } + return $rv; + } +:> + + <: $sectcounter[%0]++; sectcounter_reset(%0+1); + $num = sectnum(%0); :> + {#MYTOC#: <:= $num :> %body
:##} + ><:= $num :> %body> + print $num;:##} + /> /> +
+{#REF%0#} + +
%body
+
+ +
%body
+
+ +
%body
+
+ +
%body
+
+ +
%body
+
+ + + +{#TITLE#} + + + diff --git a/Documentation/wmlinc/common.wml b/Documentation/wmlinc/common.wml new file mode 100644 index 0000000..407a0e8 --- /dev/null +++ b/Documentation/wmlinc/common.wml @@ -0,0 +1,117 @@ + + + + + {: [[s/(?)(d\.+[-\w]+)/\1<\/code>/g]] + %body + :} + + + + + + + + %body + +/> + + + + %body + +/> + + + + + + +
+ +
+

+ + + + + + + + + + + + +
+ +
+

%body +

+
+ + + + +

Abstract

+

+ %body + + +

+ +You are reading an ugly version of this document that doesn't use CSS +to place floats nicely. Figures are shown in a very crude way. +Get Mozilla and see the other version - it's MUCH better. + + + />/> + + + + + +

+
+ +
+

+ %body +

+ + +
+ + +
+

Abstract

+

+ %body +

+
+ +

+ +Note that this document contains some formatting that is best rendered +using a true CSS1 standard-compliant browser such as Mozilla; however, +it should work reasonably well with any browser that can at least ignore +CSS that it doesn't understand. Unfortunately, Netscape Navigator 4.7, +for example, doesn't. Well, that's life... + +

+A non-CSS version exists: you can try by compiling this +document from its WML version with some switches.. (if you came here +through the WWW, there should be an alternate link on the referring +page. However, I like +the pretty rendering by Mozilla so much that that's still the default. + + /> +/> + +#use wml::std::grid +#use wml::fmt::isolatin diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..fa5d03f --- /dev/null +++ b/INSTALL @@ -0,0 +1,5 @@ +INSTALL +======= + +As described in README, this package contains several implementations, +which contain their own READMEs (and possibly INSTALL) files. diff --git a/Java/.gvimrc b/Java/.gvimrc new file mode 100644 index 0000000..75ce836 --- /dev/null +++ b/Java/.gvimrc @@ -0,0 +1,2 @@ +set cindent +set shiftwidth=4 diff --git a/Java/ApplitudeMgr.java b/Java/ApplitudeMgr.java new file mode 100644 index 0000000..54222da --- /dev/null +++ b/Java/ApplitudeMgr.java @@ -0,0 +1,310 @@ +/* +ApplitudeMgr.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; +import java.util.*; + +/** Routines related to applitude management. + * This handles registering and identification of applitudes. An applitude + * has a name and a number of params. Currently, the only used param is + * the View param, which is simply a view (as a ZOb). That ought to change + * into something more sophisticated...
+ * Applitudes are associated with dimensions. If a cell is connected on one + * of an applitude's dimensions, it is said to be "in" that applitude.
+ * XXX need to make this faster! + */ + +public class ApplitudeMgr { +public static final String rcsid = "$Id: ApplitudeMgr.java,v 1.10 2000/12/31 15:15:50 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + private static ZZCell getDimCell(ZZCell c0) { + ZZSpace s = c0.getSpace(); + ZZCell c = ZZDefaultSpace.findOnClientlist(s, "Applitudes", false); + if(c == null) return putDefApps(s.getHomeCell()); + return c.getOrNewCell("d.1", 1); + } + + /** Get a list of all the applitudes a cell is in. + */ + static public ZZCell[] getApplitudes(ZZCell c) { + ZZCell d = getDimCell(c); + ZZCell app = null; + boolean added = false; + Vector v = new Vector(); + for(d = d.s("d.2"); d != null; d = d.s("d.2")) { + if(d.s("d.1") != null) { app = d.s("d.1"); added = false; } + if(!added && (c.s(d.t()) != null || c.s(d.t(), -1) != null)) { + v.addElement(app); + added = true; + } + } + + ZZCell[] res = new ZZCell[v.size()]; + for(int i=0; i + * If the bindings cursor doesn't exist, it is created. If no applitude + * is set or something else goes wrong, though, null is returned. + */ + static public ZZCell getAppBindsForWin(ZZCell win) { + ZZCell app = getWindowApp(win); + if(app == null) return null; + ZZCell binds = win.intersect("d.app-bind", 1, app, "d.clone", 1); + ZZCell c = null; + if(binds != null) c = ZZCursorReal.get(binds); + if(c != null) return c; + + // CREATE + c = ZZDefaultSpace.findInheritableParam(app.s("d.1"), "Bindings"); + if(c == null) return null; + c = c.s("d.1"); + if(c == null) return null; + if(binds == null) { + binds = app.zzclone(); + win.insert("d.app-bind", 1, binds); + } + ZZCursorReal.set(binds, c); + return c; + } + + static public void setAppBindsForWin(ZZCell win, ZZCell to) { + ZZCell app = getWindowApp(win); + if(app == null) { + ZZLogger.log("Argh: Tried to set app binds for win without app"); + return; + } + ZZCell curs = win.intersect("d.app-bind", 1, app, "d.clone", 1); + if(curs == null) { + curs = app.zzclone(); + win.insert("d.app-bind", 1, curs); + } + ZZCursorReal.set(curs, to); + } + + /** Move to next or previous applitude for this window. */ + static public void rotateWindowApp(ZZCell win, int dir) { + ZZCell app = getWindowApp(win); + if(dir < 0) { + app = app.s("d.2", -1); + if(app.s("d.2", -1) == null) app = app.h("d.2", 1); + } else { + if(app.s("d.2") != null) app = app.s("d.2"); + else app = app.h("d.2").s("d.2"); + } + setWindowApp(win, app); + pa("Set win "+win+" to app "+app); + } +} \ No newline at end of file diff --git a/Java/BuildInfo.java.in b/Java/BuildInfo.java.in new file mode 100644 index 0000000..5c4d11c --- /dev/null +++ b/Java/BuildInfo.java.in @@ -0,0 +1,39 @@ +/* -*- Java -*- */ +/* +BuildInfo.java.in + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag; + +// THE FILE BuildInfo.java IS AUTOGENERATED FROM BuildInfo.java.in. +// Modifications to BuildInfo.java are discarded + +/** A class generated at build time, to retain info about the build. + * Currently only a single string describing the build. + */ + +public final class BuildInfo { + // Don't edit the at signs, they're placeholders used in Makefile. + /** The build date, time and builder. + */ + public static final String info = "@@@@@"; +} diff --git a/Java/ChkVersion.java b/Java/ChkVersion.java new file mode 100644 index 0000000..3dd818d --- /dev/null +++ b/Java/ChkVersion.java @@ -0,0 +1,94 @@ +/* +Main.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + + +package org.gzigzag; + +import java.lang.reflect.*; + +/** A simple class that prints the RCSIds for a number of ZZ classes. + * Eventually this'll go to the structure but for now, this is a simple + * enough way to make sure what someone is actually running. + */ + +public class ChkVersion { +public static final String rcsid = "$Id: ChkVersion.java,v 1.5 2000/09/19 10:31:58 ajk Exp $"; + + + static final String[] classes = new String[] { + "ZZCell", + "ZZCellScroll", + "ZZDefaultSpace", + "ZZError", + "ZZSimpleClient2", + "ZZApplet", + "ZZ2DBlob", + "ZZ2DCanvas", + "ZZ2DCanvasRaster", + "ZZ2DCanvasView", + "ZZViewComponent", + "ZZAbstractView", + "ZZCellRenderer", + "ZZCellRenderer1", + "ZZCompound", + "ZZSpace", + "ZZEventQueue", + "ZZExec", + "ZZGlobal", + "ZZHash", + "ZZKeyBindings", + "ZZKeyBindings1", + "ZZLinkRenderer", + "ZZLinkRenderer1", + "ZZList", + "ZZLocal", + "ZZPath", + "ZZPhotoView", + "ZZRemote", + "ZZSingleCellView", + "ZZTextView", + "ZZTraverseCB", + "ZZXML1", + "ZZUpdateManager" + }; + + + static final void p(String s) { System.out.println(s); } + public static void main(String argv[]) { + p("GZigZag checkversion --- my own id: "+rcsid); + p("Main id: "+Main.rcsid); + for(int i=0; iaction
to provide functionality to an + * option. + * + * @see HelpOption + */ + public static class Option { + /** The name of this option. A dash will be automatically + * appended to this name to produce the string that is matched + * against in command line. */ + public final String name; + + /** A list of argument names for this option. The option will + * take as many mandatory arguments as there are elements in + * this array. The names of the arguments are purely + * documentary and are used in help screens. + * + * @see org.gzigzag.CommandLineOptionsParser.HelpOption + */ + public final String[] argNames; + + /** A help text for this option. The text will be + * word-wrapped; newlines embedded in the text are + * honoured. + * + * @see org.gzigzag.CommandLineOptionsParser.HelpOption + */ + public final String helpText; + + /** The action for this option. This method will be invoked + * when this option is noticed. + * + * @param clop The instance of + * CommandLineOptionsParser that is running this + * parse. + * @param args The arguments given on the command line to this + * option. This array will have exactly as many elements as + * the argNames attribute. + */ + public void action(CommandLineOptionsParser clop, String[] args) {} + + /** Constructs an option. + * + * @param name The value to be given to the name + * attribute. + * @param argNames The value to be given to the + * argNames attribute. + * @param helpText The value to be given to the + * helpText attribute. + */ + public Option(String name, String[] argNames, String helpText) { + this.name = name; + this.argNames = argNames; + this.helpText = helpText; + } + } + + /** A command-line option for showing help about command-line + * options. */ + public static class HelpOption extends Option { + /** Constructs a HelpOption. + * @param name The name for this option (a dash will be + * automatically prepended to create the string that is + * matched against the command line). + * @param helpText The help text for this option. This text + * will be word-wrapped. Embedded newlines are honoured. + * @param exitAfter Should the program be exited after showing + * the help? + * @param prologue Text to be shown before the list of + * options. This text will be word-wrapped. Embedded + * newlines are honoured. + * @param epilogue Text to be shown before the list of + * options. This text will be word-wrapped. Embedded + * newlines are honoured. + */ + public HelpOption(String name, String helpText, boolean exitAfter, + String prologue, String epilogue) { + super(name, new String[0], helpText); + this.exitAfter = exitAfter; + this.prologue = prologue; + this.epilogue = epilogue; + } + + public void action(CommandLineOptionsParser clop, String[] args) { + int rightmargin = 75; + System.out.println(breakToLines(prologue, rightmargin, 0)); + for (Enumeration e = clop.options_in_order.elements(); + e.hasMoreElements();) { + Option opt = (Option)e.nextElement(); + int expltab = 15; + int nametab = 3; + int seplen = 2; + String help = breakToLines(opt.helpText, rightmargin, + expltab + nametab + seplen); + String name = "-" + opt.name; + for (int i = 0; i < opt.argNames.length; i++) { + name += " " + opt.argNames[i]; + } + if (name.length() > expltab) { + help = spaces(nametab) + name + '\n' + help; + } else { + help = spaces(nametab) + name + + spaces(seplen + expltab - name.length()) + + help.substring(expltab + nametab + seplen); + } + System.out.println(help); + } + System.out.println(breakToLines(epilogue, rightmargin, 0)); + if (exitAfter) SafeExit.exit(0); + } + + private String spaces(int n) { + StringBuffer sb = new StringBuffer(n); + for (int i = 0; i < n; i++) sb.append(' '); + return new String(sb); + } + + private int breakpoint(String s, int start, int maxlen) { + if (s.length() - start < maxlen) return s.length(); + int bp = start + maxlen < s.length() ? start + maxlen : s.length(); + for (int i = 0; i < maxlen && i + start < s.length(); i++) { + int c = s.charAt(start + i); + if (c == '\n') return start + i; + if (c == '\t' || c == ' ') bp = start + i; + } + return bp; + } + + private String breakToLines(String s, int rmargin, int indent) { + int maxlen = rmargin - indent; + StringBuffer sb = new StringBuffer(); + String ind = spaces(indent); + int a = 0; + while (a < s.length()) { + int b = breakpoint(s, a, maxlen); + sb.append(ind); + sb.append(s.substring(a, b)); + sb.append('\n'); + if (b < s.length() && + (s.charAt(b) == '\n' + || s.charAt(b) == ' ' + || s.charAt(b) == '\t')) { + ++b; + } + a = b; + } + return new String(sb); + } + + private final boolean exitAfter; + private final String prologue; + private final String epilogue; + } + + /** Constructs a command line options parser. + * @param options An array of preconstructed options. + * @see #put(Option) + */ + public CommandLineOptionsParser(Option[] options) { + for (int i = 0; i < options.length; i++) { + put(options[i]); + } + } + + /** Constructs a command line options parser with an initially + * empty set of acceptable options. */ + public CommandLineOptionsParser() {} + + /** Adds option to the list of valid options. */ + public void put(Option option) { + options.put(option.name, option); + options_in_order.addElement(option); + } + + /** Adds a new option to the list of valid options. The option + * object will be a new instance of class Option. + * The arguments of this method are passed unchanged to the + * constructor. + * @see Option + */ + public void put(String name, String[] argNames, String helpText) { + put(new Option(name, argNames, helpText)); + } + + /** Adds a help option to the list of valid options. The option + * object will be a new instance of HelpOption. The + * arguments of this method are passed unchanged to the + * constructor. + * @see HelpOption + */ + public void putHelp(String name, String helpText, boolean exitAfter, + String prologue, String epilogue) { + put(new HelpOption(name, helpText, exitAfter, prologue, epilogue)); + } + + /** Marks all options unseen. */ + public void clearArgs() { + optargs = new Hashtable(); + } + + /** Gets the list of arguments for the option specified. + * @param name The name of the option whose arguments are to be returned. + * @return null, if the option has not been seen, otherwise the + * same array or a copy of the same array that the + * action method of Option gets. + */ + public String[] getArgs(String name) { + Object o = optargs.get(name); + if (o == null) return null; + return (String[]) o; + } + + /** Gets a specific argument for the option specified. + * @param name The name of the option whose argument is to be + * returned + * @param i The ordinal number of the argument to be returned (0 + * for the first argument, 1 for the second and so on) + * @return null, if the option has not seen, otherwise the + * ith (0-based) argument to the option. + */ + public String getArg(String name, int i) { + return getArg(name, i, null); + } + + /** Gets a specific argument for the option specified. + * @param name The name of the option whose argument is to be + * returned + * @param i The ordinal number of the argument to be returned (0 + * for the first argument, 1 for the second and so on) + * @param deflt The object to be returned if the option has not + * been seen. + * @return deflt, if the option has not seen, otherwise the + * ith (0-based) argument to the option. + */ + public String getArg(String name, int i, String deflt) { + String[] args = getArgs(name); + if (args == null) return deflt; + return args[i]; + } + + /** Determines whether the specified option was seen in parses + * since the arguments were last cleared. */ + public boolean seen(String name) { + return optargs.containsKey(name); + } + + /** Parse command-line options from args and return the first + * index to attrs that is not an option, or attrs.length if there + * are none such . */ + public int parse(String[] args) { + int i; + for (i = 0; i < args.length; i++) { + if (args[i].length() == 0 || args[i].charAt(0) != '-') { + return i; + } + + if (!options.containsKey(args[i].substring(1))) { + throw new SyntaxError("unknown option: " + args[i]); + } + + Option opt = (Option)options.get(args[i].substring(1)); + String[] oargs = new String[opt.argNames.length]; + for (int j = 0; j < oargs.length; j++) { + ++i; + if (i >= args.length) { + throw new SyntaxError("too few arguments to option: -" + opt.name); + } + oargs[j] = args[i]; + } + optargs.put(opt.name, oargs); + opt.action(this, oargs); + } + return i; + } + + private Hashtable options = new Hashtable(); + private Vector options_in_order = new Vector(); + + private Hashtable optargs = new Hashtable(); + + +} diff --git a/Java/Dump.java b/Java/Dump.java new file mode 100644 index 0000000..c16c239 --- /dev/null +++ b/Java/Dump.java @@ -0,0 +1,242 @@ +/* +Dump.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A class to dump part of a zzspace in a cvsable way. + * XXX sort for id when dumping! (elsewise, cvs won't be usable) + * XXX make spans work correctly + * XXX make work for dumping + */ + +public class Dump { +public static final String rcsid = "$Id: Dump.java,v 1.3 2000/12/24 13:54:20 bfallenstein Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static final int fmtversion = 2; // Version of Dump format + + /** Retrieve and check id for cell. + * IDs must either be numbers (given as Strings XXX should use Integer?) + * or correct Java identifiers. + */ + private static String id(ZZCell c, Hashtable ids) { + String s = (String)ids.get(c); + if(s.length() == 0) throw new ZZError("Empty Dump cell id"); + // Check if it's a number; if not, the exception is thrown + try { + Integer.parseInt(s); + } catch(NumberFormatException e) { + // Not a number. Now, test if it's a valid Java identifier. + if(!Character.isJavaIdentifierStart(s.charAt(0))) + throw new ZZError("Bad Dump cell id: '"+s+"'"); + for(int i=1; ibetween them on + * the dimensions given, exclusively. + * @param ids A hashtable mapping cells to ids. This must contain an entry + * for every cell in cells[], and there may not be any entry + * for a cell not in cells[]. + */ + public static void writeDump(ZZCell[] cells, String[] dims, + Hashtable ids, int nextid, String title, + Writer writer) { + PrintWriter w = new PrintWriter(writer); + w.println("HEADER"); w.println(); + w.println("Format: Dump "+fmtversion); + w.println("Title: "+title); + w.println("rcsid: $Id: Dump.java,v 1.3 2000/12/24 13:54:20 bfallenstein Exp $"); + if(nextid >= 0) w.println("Next free ID: "+nextid); + + w.println(); w.println(); + w.println("CONTENTS"); w.println(); + for(int i=0; i 0) { + ZZCell c1 = (ZZCell)todo.elementAt(0); + todo.removeElementAt(0); + + for(int i=0; i + *

  • A subspace (SP) has a handle cell (HC). + *
  • The HC is connected to a cell of the subspace on +d.dump-conn + *
  • The HC contains the SP file name. + *
  • Connected to the HC on +d.2 is a rank with dim names; only these dims + * are saved to the SP file. + *
  • After loading, every cell in the SP has a connection on +d.dump-id. The + * id found in that cell is a Java identifier for the cell. + *
  • Connected to the HC on +d.dump-nextid is the next free numeric id for + * SP cells (if not present, assumed to be 1). When dumping, this is used + * to create ids for cells without +d.dump-id connections; the number is + * prepended with a 'c' in that case to make it a valid Java identifier. + * + * Dump IDs may be changed to something more meaningful. When a java class + * is created from the dump by dump2java.pl, they are instance variables. + */ + +public class Dumper { +public static final String rcsid = "$Id: Dumper.java,v 1.2 2000/12/22 22:44:34 bfallenstein Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public void create(ZZCell from) { + ZZCell hdl = from.N("d.1"); + hdl.setText("MyDump"); + hdl.N("d.dump-nextid").setText("2"); + hdl.N("d.2").setText("d.3"); + hdl.N("d.2").setText("d.2"); + hdl.N("d.2").setText("d.1"); + ZZCell c1 = hdl.N("d.dump-conn"); + c1.N("d.dump-id").setText("1"); + } + + static public void write(ZZCell hdl, Writer writer) { + String title = hdl.t(); + ZZCell[] dcs = hdl.readRank("d.2", 1, false); + String[] dims = new String[dcs.length]; + for(int i=0; i 0) hdl.N("d.dump-nextid").setText(""+r.nextid); + else hdl.N("d.dump-nextid").setText("1"); + + for(int i=0; i=0; i--) + hdl.N("d.2").setText(r.dims[i]); + + if(r.cells.length > 0) + hdl.connect("d.dump-conn", 1, r.cells[0]); // save start cell! + else + ZZLogger.log("Strange: Dump without cells..."); + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + if(id.equals("Dump")) + write(target, new OutputStreamWriter(System.out)); + else if(id.equals("Write")) { + try { + write(target, new FileWriter(target.t()+".zzd")); + ZZLogger.log("Successfully written dump: "+target.t()); + } catch(IOException e) { ZZLogger.exc(e); } + } else if(id.equals("Read")) { + try { + read(target, new FileReader(target.t()+".zzd")); + } catch(FileNotFoundException e) { ZZLogger.exc(e); } + } else if(id.equals("Create")) create(target); + else if(id.equals("Enter")) { + ZZCell vc = view.getViewcell(); + ZZCell to = ZZCursorReal.get(vc).s("d.dump-conn"); + if(to != null) ZZCursorReal.set(vc, to); + } else if(id.equals("ChangeID")) { + ZZCell vc = view.getViewcell(); + ZZCell acc = ZZCursorReal.get(vc); + ZZCell to = acc.s("d.dump-id"); + if(to == null) to = acc.h("d.dump-id", true); + if(to == null) to = acc.N("d.dump-id"); + ZZCursorReal.set(vc, to); + } + } + + public ZOb newZOb(String id) { + return null; + } + }; +} \ No newline at end of file diff --git a/Java/JEv.java b/Java/JEv.java new file mode 100644 index 0000000..71dbf0e --- /dev/null +++ b/Java/JEv.java @@ -0,0 +1,73 @@ +/* +JEv.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; + +/** A program to simply print out events as they come. + * The point is to see what keyboard events actually contain on + * different platforms. + */ + +public class JEv { + public static void l(KeyEvent e) { + System.out.println(e); + System.out.println("Txt: \""+e.getKeyText(e.getKeyCode())+"\"\n"); + } + public static void l(MouseEvent e) { + System.out.println(e); + System.out.println("Mouse: "+e.getModifiers()); + } + + public static void main(String[] argv) { + Frame f = new Frame(); + f.setSize(300,300); + f.show(); + f.addKeyListener(new KeyListener() { + public void keyTyped(KeyEvent e) { l(e); } + public void keyPressed(KeyEvent e) { l(e); } + public void keyReleased(KeyEvent e) { l(e); } + }); + f.addMouseMotionListener(new MouseMotionListener() { + public void mouseDragged(MouseEvent e) { l(e); } + public void mouseMoved(MouseEvent e) { l(e); } + }); + f.addMouseListener(new MouseListener() { + public void mouseClicked(MouseEvent e) { l(e); } + public void mousePressed(MouseEvent e) { l(e); } + public void mouseReleased(MouseEvent e) { l(e); } + public void mouseEntered(MouseEvent e) { l(e); } + public void mouseExited(MouseEvent e) { l(e); } + }); + + + + while(true) { + try { Thread.sleep(1000); } + catch(Exception e) { + ZZLogger.exc(e); + } + System.out.println("------"); + } + } +} diff --git a/Java/LoopDetector.java b/Java/LoopDetector.java new file mode 100644 index 0000000..ac17210 --- /dev/null +++ b/Java/LoopDetector.java @@ -0,0 +1,66 @@ +/* +LoopDetector.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A loop detector. + * Uses a simple constant-space algorithm that will detect any loop before + * it's cycled through 3 times, except very small loops. + * Example use: + *
    + * 	LoopDetector l = new LoopDetector();
    + *	while((x = iter(x)) != null) {
    + *		l.detect(x);
    + *		// ... do something with x.
    + *	}
    + * 
    + * Note: this only works for deterministic loops that always have the same + * elements and length. + *

    + * The Object.equals method is used for the comparisons. + */ + +public final class LoopDetector { +public static final String rcsid = "$Id: LoopDetector.java,v 1.6 2000/11/02 13:03:08 tjl Exp $"; + Object obj = this; + int count = 0; + int nth = 10; + public void reset() { count = 0; obj = null; } + /** Throws an error if the parameter is a part of a looping sequence. + */ + public void detect(Object o) { + if(isLooping(o)) + throw new ZZInfiniteLoop("Infinite loop detected"); + } + /** Returns true if the parameter is a part of a looping sequence. + */ + public boolean isLooping(Object o) { + if(o.equals(obj)) return true; + if(count-- < 0) { + nth *= 2; + count = nth; + obj = o; + } + return false; + } +} diff --git a/Java/Main.java b/Java/Main.java new file mode 100644 index 0000000..8f81d68 --- /dev/null +++ b/Java/Main.java @@ -0,0 +1,535 @@ +/* +Main.java + * + * Copyright (c) 1999, 2000 Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, version control by Tuukka Hastrup, + * space locking by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag; + +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; +import java.lang.reflect.*; + +/** The class to run to start the ZZ client. + * This class parses the command line, prepares the space and starts the + * client. If needed, a new client space with default settings is created. + * + * The one obligatory argument to give this program is the name of the file + * to use for the cellscroll of the main space. + * Additionally, the following options can be given. + *

    + *
    -new + *
    Recreate the default client space starting from + * the main cell. This is important if the internal + * client structures used by GZigZag have changed since + * the space was created, or if this is a new space. + * If the cellscroll file given does not exist, + * this is the default. + * If the file already exists, the old system list + * and the list on d.2 down from the home cell + * are placed on the d.2 list, at a cell named + * OldSysList (see ZZDefaultSpace). + *
    -convert + *
    Convert an old, incompatible, space to compatible form. + * When conversion is needed, it will be told by the + * program. Taking backup before conversion is + * recommended. After conversion you might need to use + * new and dcold to catch up with + * configuration changes. + *
    -import XMLfile + *
    When creating a new space, you can import an XML + * file describing the space. + *
    -export XMLfile + *
    Export the whole space to the specified file + *
    -recrmdim +
    Recreate master dimension list from data on disk. + *
    -dbg classname + *
    Turn on debugging in the given class. For developers + * only. + *
    -pda + *
    Run in PDA-mode. + *
    -span + *
    Save information about cells whose spans overlap. + * This may be slow at the moment, but is necessary + * to show e.g. the overlaps of two nile text streams. + *
    -ztpserv PORT + *
    Invoke the ZTP server code instead of the ZZ client code. + * Listen on the TCP port PORT for incoming connections. + *
    -dump + *
    Dump the space to the file CELLSCROLLFILE.dmp (where + * CELLSCROLLFILE is the name of the space file). + * + *
    -slurp FILENAME + *
    Slurp the space from the file called FILENAME. + *
    -versioneddims + *
    Show connections from old versions along regular dimensions + * in addition to the special version: dimensions. + * + *
    + *

    + * Some Filenames that start with ':' are special. For example, + * ':DS' starts with the ZZDimSpace instead of normal persistent space. + * You should probably only use these if you are hacking the core. + *

    + * Example: + *

    + * 	java foo.Main -new /tmp/foo
    + * 
    + * opens the cellscroll at /tmp/foo and creates the new client structure. + * XXX Make a good system for specifying the type. + *

    + * Currently, if you give extra arguments after the file name, the system + * creates a ZZSlicedDimSpace instead. + * BE VERY CAREFUL WITH THIS! Once you put some slices there with a given + * root space, never leave them out or confusion will result. + * This feature should NOT be used if you're not prepared to hack the + * storage/*Slice* code. + */ + +public class Main { +public static final String rcsid = "$Id: Main.java,v 1.70 2001/03/29 13:06:07 ajk Exp $"; + public static final boolean dbg = true; + public static int zzclientversion = 2; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + /** For storing the classes whose debug prints are turned on. + * Otherwise they might get garbage collected and debugging not + * stay turned on. + */ + static Vector dbgclasses = new Vector(); + + /** Make this class print debug info. + * Any callers from outside Main must provide their own Vector + * to put the class objects in in order to avoid garbage collection. + */ + public static void debugClass(String name, Vector into) { + try { + p("Turning on debugging for class "+name); + Class clazz = Class.forName("org.gzigzag."+name); + Field f = clazz.getField("dbg"); + f.setBoolean(null, true); + into.addElement(clazz); + into.addElement(f); + } catch(Exception e) { + e.printStackTrace(); + pa(""+e); + throw new Error("Error while turning on debug info"); + } + } + + + public static void main(String argv[]) { + + pa("Starting gZigZag client, build: "+BuildInfo.info); + pa("Clientspace version used by program is "+zzclientversion+"."); + try { + Class primact = Class.forName("org.gzigzag.ZZPrimitiveActions"); + // *** Parse command line + + if(argv.length < 1) { + System.err.println("No filename given"); + SafeExit.exit(1); + } + CommandLineOptionsParser clop = new CommandLineOptionsParser(); + String[] noargs = new String[0]; + clop.put("pda", noargs, "run in PDA mode"); + clop.put("new", noargs, + "Recreate the default client space " + + "starting from the main cell. This " + + "is important if the internal client " + + "structures used by GZigZag have changed " + + "since the space was created, or if this " + + "is a new space. If the cellscroll file " + + "given does not exist, this is the default. " + + "If the file already exists, the old system " + + "list and the list on d.2 down from the home " + + "cell are placed on the d.2 list, at a cell " + + "named OldSysList (see ZZDefaultSpace)."); + clop.put("import", new String[] { "XMLFILE" }, + "When creating a new space, you can import an XML " + + "file describing the space."); + clop.put("export", new String[] { "XMLFILE" }, + "Export the whole space to the specified file"); + clop.put("convert", noargs, + "Convert an old, incompatible, space to compatible " + + "form. When conversion is needed, it will be " + + "told by the program. Taking backup before " + + "conversion is recommended. After conversion you " + + "might need to use -new and -dcold to catch up " + + "with configuration changes."); + clop.put("xmlencoding", new String[] { "ENCODING" }, + "Specify the character encoding used by the " + + "XML export function."); + clop.put("ztpserv", new String[] { "PORT" }, + "Invoke the ZTP server code instead of the ZZ " + + "client code. Listen on the TCP port PORT for " + + "incoming connections."); + clop.put("recrmdim", noargs, + "Recreate master dimension list from data on disk."); + clop.put("foolconvert", noargs, "???"); + clop.put("textlog", noargs, "???"); + clop.put("verboselog", noargs, "???"); + clop.put("span", noargs, "Save information about cells whose " + + "spans overlap. This may be slow at the moment, " + + "but is necessary to show e.g. the overlaps of " + + "two nile text streams."); + clop.put("dump", noargs, "Dump the space to the file " + + "CELLSCROLLFILE.dmp (where CELLSCROLLFILE is the " + + "name of the space file)."); + clop.put("slurp", new String[] { "FILENAME" }, + "Slurp the space from the file called FILENAME."); + clop.put("versioneddims", noargs, + "Show connections from old versions along regular " + + "dimensions in addition to the special version: " + + "dimensions."); + clop.put(new CommandLineOptionsParser.Option("dbg", new String[] { "CLASSNAME" }, + "Turn on debugging " + + "in the given " + + "class. For " + + "developers only.") { + public void action(CommandLineOptionsParser clops, + String[] args) { + debugClass(args[0], dbgclasses); + } + + }); + clop.putHelp("help", "shows this help screen", true, + "Usage:\nGZigZag takes one mandatory parameter: the name " + + "of the directory where the space is (to be) stored. " + + "Additionally, one or more of the following options " + + "may be specified before the directory name.", + ""); + int cur = clop.parse(argv); + + // Since local classes cannot modify these, we have to do + // this ugly thing... + boolean newspace=clop.seen("new"); // New client space? + boolean textlog=clop.seen("textlog"); + boolean verboselog=clop.seen("verboselog"); + boolean pda=clop.seen("pda"); + boolean span=clop.seen("span"); // Use a SpanSet to find overlapping spans? + boolean ztpserv=clop.seen("ztpserv"); + boolean dump=clop.seen("dump"); + String slurpf=clop.getArg("slurp", 0); + int ztpport=Integer.parseInt(clop.getArg("ztpserv", 0, "0")); + + boolean recreateMasterDimList=clop.seen("recrmdim"); + boolean convert=clop.seen("convert"); // Convert client space version? + boolean foolconvert=clop.seen("foolconvert"); + String importFile=clop.getArg("import", 0, ""); // If nonempty, it'll be imported + String exportFile=clop.getArg("export", 0, ""); // If nonempty, we'll export + String encoding = clop.getArg("xmlencoding", 0, "UTF-8"); // for exporting + clop = null; // we no longer need it, throw it away + + if ( argv[cur].startsWith("-") ){ + // we don't want filenames to look like args + System.err.println("Unknown arg "+argv[cur]); + cur++; + //SafeExit.exit(1); + } + + if(argv.length < cur+1) { + System.err.println("No filename given"); + SafeExit.exit(1); + } + + if(textlog) { + ZZPrimitiveActions.textlog = + new PrintWriter(new FileOutputStream( + argv[cur] + ".txt", true)); + } + + if(verboselog) { + ZZLogger.logfile = + new PrintWriter(new FileOutputStream(argv[cur] + ".log", true)); + + } + + // *** Prepare the space: create ZZSpace objects + + System.runFinalizersOnExit(true); // needed for unlocking a space + + String[] slices = null; + + ZZSpace space; + + if(argv[cur].equals(":DS")) { + space = new ZZDimSpace(); + newspace = true; + } else { // Space stored in file + File f = new File(argv[cur]); + if(!f.exists()) newspace = true; + if(argv.length > cur+1) { + System.err.println("SLICE TEST MODE!!!!!"); + slices = new String[argv.length-(cur+1)]; + System.arraycopy(argv, cur+1, slices, 0, + argv.length-(cur+1)); + } + space = new ZZCacheDimSpace(new DirStreamSet(f)); + if(span) ((ZZDimSpace)space).spanset = new SpanTree(); + } + + // And now we switch spaces if there are slices. + if(slices != null) { + throw new ZZError("slices are broken"); + //ZZDimSpace[] ss = new ZZDimSpace[slices.length+1]; + //ss[0] = (ZZDimSpace)space; + //for(int i=0; i 0) { + ZZLogger.tryInitSyslog(); + try { + Class ztpcl = Class.forName("org.gzigzag.module.ZTPserver"); + Constructor ztpcons = ztpcl.getConstructor(new Class[] { + Class.forName("org.gzigzag.ZZSpace"), + Class.forName("java.lang.Integer")}); + Object ztp = ztpcons.newInstance(new Object[] { space, new Integer(ztpport) }); + p("main exiting - waiting for connections"); + } catch (ClassNotFoundException e) { + ZZLogger.exc(e); + } + return; + } + + if (recreateMasterDimList) { + space.recreateMasterDimList(); + space.commit(); + } + + if(newspace && !importFile.equals("")) { + // XXX should be "if a space with only the home cell" + // NOTE: Introspection is used so that there will not + // be a compile-time dependency on the XML module. + Object xml = (Class.forName("org.gzigzag.module.XML").newInstance()); + Method get = xml.getClass().getMethod("load", new Class[] {Class.forName("java.io.File"), Class.forName("org.gzigzag.ZZCell")}); + get.invoke(xml, new Object[] {new File(importFile), space.getHomeCell()}); + space.commit(); + newspace = false; // It's old then + } + if(!exportFile.equals("")) { + // NOTE: Introspection is used so that there will not + // be a compile-time dependency on the XML module. + Object xml = (Class.forName("org.gzigzag.module.XML").newInstance()); + Method get = xml.getClass().getMethod("export", new Class[] {Class.forName("java.io.File"), Class.forName("org.gzigzag.ZZSpace"), Class.forName("java.lang.String")}); + p("Invoke: "+get+" "+xml); + get.invoke(xml, new Object[] {new File(exportFile), space, encoding}); + p("File exported - exiting."); + SafeExit.exit(0); + } + + // *** Prepare client space and check version + + // Ted asked for this kind of an announcement + if(newspace) { + System.err.println("Creating or recreating the system part of the space"); + } + ZZCell home = space.getHomeCell(); + if(newspace) { + ZZDefaultSpace.create(space.getHomeCell()); + } + if (newspace) { // Might be re-init + home.getOrNewCell("d.gzz-space-version", 1) + .setText(""+zzclientversion); + } else { + ZZCell vercell = home.s("d.gzz-space-version",1); + if(vercell==null) { + pa("Version cell not found: setting version to zero."); + vercell = home.N("d.gzz-space-version", 1); + vercell.setText("0"); + } + pa("Clientspace versionstring: '"+vercell.getText()+"'"); + int fileversion; + try { + fileversion = Integer.parseInt(vercell.getText()); + } catch (NumberFormatException e) { + fileversion = 0; + } + + pa("Clientspace version in prepared space is "+fileversion+"."); + if(fileversion > zzclientversion) + quit("Can't use files from clients that new. " + + "Please upgrade client."); + if(fileversion < zzclientversion && !convert) + quit("Files from older client. Please use " + + "option -convert after backing up the file."); + if(convert && !foolconvert) { + if(fileversion == zzclientversion) + quit("File is already of same version."); + convert(fileversion, zzclientversion, space); + vercell.setText(""+zzclientversion); + vercell.getSpace().commit(); + SafeExit.exit(0); + } + } + + /* // Print all cells + ZZCell i; + p("Cells:"); + for(Enumeration e=space.cells();e.hasMoreElements();) + { + i=(ZZCell)e.nextElement(); + p(i.getID()+": "+i.getText()); + }*/ + + // Print all dimensions + String[] dims = space.dims(); + p("Dimensions: ("+dims.length+")"); + for(int s=0;s BuildInfo.java.new && mv BuildInfo.java.new BuildInfo.java + $(JAVAC) -deprecation $(DEBUG) -d . BuildInfo.java + $(JAVAC) -deprecation $(DEBUG) -d . $(SRC) + $(archcompile) + +# If you want to try out the opengl stuff +opengl: + @echo "********************************************" + @echo "* requires gltt !! *" + @echo "* add ../Modules/openGL to LD_LIBRARY_PATH *" + @echo "********************************************" + (cd ../Modules/openGL; make) + $(JAVAC) -deprecation $(DEBUG) -d . ../Modules/openGL/*.java + +doc:: $(SRC) + sh ./make-src-tree.sh $(TEMP)/zzsrc + rm -Rf doc + mkdir doc + javadoc $(JAVADOCOPTS) -d doc -sourcepath $(TEMP)/zzsrc org.gzigzag \ + org.gzigzag.clang \ + org.gzigzag.module + rm -Rf $(TEMP)/zzsrc + +zobdoc:: $(SRC) + sh ./make-src-tree.sh $(TEMP)/zzsrc + rm -Rf zobdoc + mkdir zobdoc + javadoc -doclet org.gzigzag.ZobDoc -d zobdoc \ + -sourcepath $(TEMP)/zzsrc \ + org.gzigzag org.gzigzag.clang org.gzigzag.module + rm -Rf $(TEMP)/zzsrc + + +# perl -pi.bak -e's||"".`cat Package.html`|e' doc/Package-org.gzigzag.html + +MODULESUPPORT=no +JARMODULES=applet mbox joystick test 3d xml extern prez \ + textcloud daytimedemo hypergenealogy nile notemap zaubertrank mind +JARARCHES= +JARNAME=gzigzag.jar +jar: buildir=$(JARNAME).build +jar: + cd .. && ./makedist.sh Java/$(buildir) + -$(MAKE) -C $(buildir)/Java ARCH="$(JARARCHES)" MODULES="$(JARMODULES)" all + -$(MAKE) -C $(buildir)/Java MODULES="$(JARMODULES)" allRCH="$(JARARCHES)" + -$(MAKE) -C $(buildir)/Java ARCH="$(JARARCHES)" MODULES="$(JARMODULES)" all + $(MAKE) -C $(buildir)/Java ARCH="$(JARARCHES)" MODULES="$(JARMODULES)" all + echo 'Main-Class: org.gzigzag.Main' > $(buildir)/Java/manifest + set -e ; if [ "$(MODULESUPPORT)" != "no" ] ; \ + then \ + (cd $(buildir)/Java && jar -xvf $(MODULESUPPORT) gnu org) ;\ + fi + cd $(buildir)/Java && cp ../LICENSE.lgpl ../LICENSE.xpl . + cd $(buildir)/Java && cp ../README README.source + cd $(buildir)/Java && jar cvfm $(JARNAME) manifest fi foo xanadu gnu org README README.source LICENSE* + mv $(buildir)/Java/$(JARNAME) . + rm -rf $(buildir) + + +mvdoc: doc + scp -r doc/* tjl@gzigzag.sourceforge.net:/home/groups/gzigzag/www/javadoc/ + +%.java: %.pl + perl $< $@ + +clean: + rm -rf fi foo xanadu org + rm -f $(AUTOGENERATED) + rm -f BuildInfo.java clang/ZZClangOps.java + $(archclean) + +tags: $(SRC) + ctags $(SRC) + +CVS2CL=cvs2cl + +ChangeLog:: + $(MAKE) -C .. ChangeLog + +ncss:: $(SRC) + $(JAVANCSS) -function $(SRC) | perl mungencss.pl | \ + sort -rnk3 -k1 >ncss-ccn + sort -rnk2 -k1 ncss-ncss + sort -rnk4 -k1 ncss-jvdc +# $(JAVANCSS) -all $(SRC) >ncss + + + diff --git a/Java/NullZOb.java b/Java/NullZOb.java new file mode 100644 index 0000000..5817d18 --- /dev/null +++ b/Java/NullZOb.java @@ -0,0 +1,40 @@ +/* +NullZOb.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** An extension module implementing some Java functionality. + * Extension module classes should have a single static public member + * named module of this type. + *

    + * Clang commands implemented in extension modules are accessed + * through the Module.FUNCTION interface. + */ + +public class NullZOb implements ZOb { +String rcsid = "$Id: NullZOb.java,v 1.3 2000/09/19 10:31:58 ajk Exp $"; + public void setComponent(Component c) {} + public String readParams(ZZCell c) { return null; } +} diff --git a/Java/Package.html b/Java/Package.html new file mode 100644 index 0000000..939be7a --- /dev/null +++ b/Java/Package.html @@ -0,0 +1,9 @@ + +This package (name will probably change later) is the current home +of the GZigZag Java classes. +

    +Start from ZZCell, ZZEdit and ZZObs. +

    +Not all the documentation is there yet but this is constantly being +upgraded. Some of the classes are deprecated and most that are are +marked so. These will be removed soon. diff --git a/Java/README b/Java/README new file mode 100644 index 0000000..c5da2ea --- /dev/null +++ b/Java/README @@ -0,0 +1,146 @@ +General +======= + +Contact Tuomas Lukka at lukka@iki.fi if you want to help hack on this. + +Start the Java GZigzag through the org.gzigzag.Main class, e.g. + + java org.gzigzag.Main [options] cellscrollfile + +where the options are detailed in the javadoc for org.gzigzag.Main. + +IF IT IS TOO SLOW, CHECK THE FAQ (../Documentation/FAQ), question +II.1.5 TO GET HELP AT STARTUP, SEE ../Documentation/STARTING. There +is a quick-hack user's guide in ../Documentation/UsersGuide/ . + +Note that org.gzizgag.Main opens up two windows, showing the same +(vanishing) view of the structure. There are a lot of other views; +you can cycle a short list with `v' (data window) or `Shift-v' +(control window); more can be added to that list (Views) by cloning +views from the AllViews list. + +Note that some classes are currently work-in-progress and some are +abandoned. Some are just being tried on for size (ZZPath). See what +org.gzigzag.Main (Main.java) uses for what's reasonably current. The +truly deprecated ones will be removed little by little. Tuomas +recommends a coloring editor so you can easily see which parts are +commented out -- there are quite many of them, which will be removed +shortly. Tuomas uses gvim. + +Structure +========= + +The structure of the source is still evolving. Right now, there are +several meaningful subdirectories below this directory, including + +media/ - handling fluid media (text etc) +storage/ - how to store the ZZ information on disk in a few different formats +flob/ - all the current basic views and their support +clang/ - cellular programming language experimentation + + +Commands +======== + +See the user's guide for more info. + +Compiling +========= + +Note that some Java compilers may have trouble with dependencies so +you may have to run "make" several times. REMEMBER TO SET YOUR CLASSPATH +CORRECTLY! + +Bug reporting +============= + +Bug reports are gladly accepted. See the FAQ for more info. + +Please run + + java org.gzigzag.ChkVersion + +and include the output so we can be sure which version of each file +you're running. + + +Requirements +============ + +First of all, the center of it all: make. GNU make version 3.78.1 is +known to work. + +Java Developer's Kit, version 1.1 or later. Kaffe won't work. + +Swing is no longer required. + +Perl, version 5.004 or later, is required by the zob stuff. + +This is all you need to compile & run the core GZigZag. In the +directory ../Modules are some modules useful for various things. For +convenience, they are called from the Makefile in this directory. + +IF YOU DO NOT WANT TO INSTALL THE REQUIREMENTS FOR A MODULE, JUST +REMOVE IT FROM THE + + MODULES=... + +LINE IN THE MAKEFILE. You can also specify it on the make command +line like this: + + make MODULES="" + + +Requirements for modules +======================== + +1. xml + +To use the XML module, you need the Xerces libraries from +http://xml.apache.org, version 1.1.2 or later. +If there is a problem, please report it to me. + +2. mbox + +You need the GNU regexp libraries, version 1.0.8, for parsing mailboxes. +Note that this module is not yet very useful so it's developers only. + +3. test + +This just contains small test classes for various features and is +mostly useful for developers only. Use the source, Luke. + +4. sound + +This module requires JMF, the Java Media Framework, version 2.0, +available from java.sun.com either as a pure Java download or an accelerated +version for Solaris or NT. + +5. applet + +This module requires the XML module. If you would like to use ZZApplet +from a browser, like netscape navigator, you must have OpenXML +libraries in the path the browsers JVM searches. Tuomas got it +working by copying openxml.jar to netscapes library directory. ( vp ) + +Documentation +============= + +The javadocs embedded in the sources (which may be converted to HTML +using the Sun javadoc program) may help quite a bit. + +See also the directory ../Documentation + + +A weird JNI Perl scripting thing +================================ + +In the script/ subdirectory there is a JNI interface to the Perl scripting +module of the C++ side, which works: this is intended as a temporary +measure to allow scripting within the Java client. Eventually this should +be replaced with the ZZ Scripting language plus TCP/IP connection to a +Perl script server, if required. Compiling the jzigzag program can be +a bit difficult but is well worth it. + + + -- The GZigZag team diff --git a/Java/RString.java b/Java/RString.java new file mode 100644 index 0000000..ddf0e34 --- /dev/null +++ b/Java/RString.java @@ -0,0 +1,41 @@ +/* +RString.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** A potentially referential immutable text string. + */ + +public interface RString { +String rcsid = "$Id: RString.java,v 1.1 2000/10/20 11:35:29 tjl Exp $"; + + String txt(); + + RString substring(int start); + RString substring(int start, int end); + + Span[] getSpans(); + Span[] getSpans(int start); + Span[] getSpans(int start, int end); + +} diff --git a/Java/SafeExit.java b/Java/SafeExit.java new file mode 100644 index 0000000..f7fe801 --- /dev/null +++ b/Java/SafeExit.java @@ -0,0 +1,95 @@ +/* +SafeExit.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag; + +import java.util.*; + +/** A class that can be told of things that need to be done at + shutdown and that will do them when it is asked to kill the + program. Since Java does not provide pre-shutdown hooks, we need + to provide them ourselves. */ +public class SafeExit { + + /** An object that wants to be called at exit time for cleanup. + */ + public interface Cleanupable { + /** Perform any cleanup operations necessary for this object. + */ + void cleanup() throws Throwable; + } + + private static Vector things_to_clean_up = new Vector(); + + public static void registerObject(Cleanupable o) { + things_to_clean_up.addElement(o); + } + + public static void unregisterObject(Cleanupable o) { + things_to_clean_up.removeElement(o); + } + + /** This is a safe exit procedure that kills all threads first, + then cleans up those things that are registered for cleanup + and then exits. */ + public static void exit(int exitcode) { + // The following is from "The Java Programming Language", + // Second Edition, p. 329--330 + + // this needs the threads to be modified so that they end on + // interrupt or something, so now this is disabled +// Thread myThread = Thread.currentThread(); +// ThreadGroup thisGroup = myThread.getThreadGroup(); +// int count = thisGroup.activeCount(); +// Thread[] threads = new Thread[count + 20]; +// thisGroup.enumerate(threads); + +// for (int i = 0; i < threads.length; i++) { +// if (threads[i] != null && threads[i] != myThread) { +// threads[i].interrupt(); +// } +// } + +// for (int i = 0; i < threads.length; i++) { +// if (threads[i] != null && threads[i] != myThread) { +// try { +// threads[i].join(); +// } catch (InterruptedException e) { +// // ignore +// } +// } +// } + + // Ok, now to our own stuff: clean up + for (Enumeration e = things_to_clean_up.elements(); + e.hasMoreElements();) { + Cleanupable o = (Cleanupable) e.nextElement(); + try { + o.cleanup(); + } catch (Throwable t) { + ZZLogger.exc(t, "At cleanup"); + } + } + + System.exit(exitcode); + } + +} diff --git a/Java/ScalableFont.java b/Java/ScalableFont.java new file mode 100644 index 0000000..4cb5fa8 --- /dev/null +++ b/Java/ScalableFont.java @@ -0,0 +1,122 @@ +/* +ScalableFont.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Rauli Ruohonen + */ + +package org.gzigzag; +import java.awt.*; +import java.util.*; + +/** A font object from which it is easy to obtain + * instances and metrics scaled to requested multiplications. + */ + +public class ScalableFont { + public static final String rcsid = "$Id: ScalableFont.java,v 1.3 2001/01/01 01:20:22 raulir Exp $"; + public static boolean dbg=false; + private static final void p(String s) { if(dbg) ZZLogger.log(s); } + + /** If set, font metrics will not be cached. + */ + public static boolean dontCache=false; + + /** Used to get FontMetrics for a Font. + * Should be set in e.g. main(). + */ + public static Component fmComp; + + /** The font and font metrics caches. + */ + private static Hashtable fCache=new Hashtable(),fmCache=new Hashtable(); + + /** The font family. + */ + private String fam; + + /** The font style. + */ + private int st; + + /** The point size when scaling factor is 1. + */ + private int defPt; + + /** Constructor similar to Java's Font(f,s,p). + * @param pointsize Point size when scaling factor is 1. + */ + public ScalableFont(String family,int style,int pointsize) { + fam=family; + st=style; + defPt=pointsize; + } + + /** Get a scaled instance of the font. + * @param scale Scaling factor is (scale/1000). + * @return May not return null. + */ + public Font getFont(int scale) { + int pt=scale2pt(scale); + return getFontPtId(pt,fam+"/"+st+"/"+pt); // XXX I dislike the ID -tjl + } + + /** Get font metrics for a scaled instance of the font. + * @param scale Scaling factor is (scale/1000). + * @return May not return null. + */ + public FontMetrics getFontMetrics(int scale) { + int pt=scale2pt(scale); + String id=fam+"/"+st+"/"+pt; + Font f=getFontPtId(pt,id); + + if(dontCache) return fmComp.getFontMetrics(f); + + FontMetrics fm=(FontMetrics)fmCache.get(id); + + if(fm==null) { + p("FontMetrics cache miss: "+id); + fm=fmComp.getFontMetrics(f); + fmCache.put(id,fm); + } + return fm; + } + + + + private static Font lastFont; + private static String lastId=""; + + private synchronized Font getFontPtId(int pt,String id) { + if(lastId.equals(id)) return lastFont; + lastId=id; + if(dontCache) lastFont=new Font(fam,st,pt); + else { + lastFont=(Font)fCache.get(id); + if(lastFont==null) { + p("Font cache miss: "+id); + lastFont=new Font(fam,st,pt); + fCache.put(id,lastFont); + } + } + return lastFont; + } + private int scale2pt(int scale) { + return (defPt*scale+500)/1000; + } + +} diff --git a/Java/SoundObs.java b/Java/SoundObs.java new file mode 100644 index 0000000..37b6888 --- /dev/null +++ b/Java/SoundObs.java @@ -0,0 +1,37 @@ +/* +SoundObs.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** Called by SoundScroll when things happen. + */ +public interface SoundObs { +String rcsid = "$Id: SoundObs.java,v 1.3 2000/09/19 10:31:58 ajk Exp $"; + + int STARTED = 42; + int PLAYING = 43; + int STOPPED = 44; + void playingAt(int event, long l); +} + diff --git a/Java/SpaceDump.java b/Java/SpaceDump.java new file mode 100644 index 0000000..a05b069 --- /dev/null +++ b/Java/SpaceDump.java @@ -0,0 +1,164 @@ +/* +SpaceDump.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +/** A space dump class. This class is used to dump the whole space + * into a specially formatted text file designed to allow carrying on + * information from any space version to the next and to parse the + * aforementioned text file. */ + +package org.gzigzag; +import java.io.*; +import java.util.*; + +public class SpaceDump { +public static final String rcsid = "$Id: SpaceDump.java,v 1.3 2001/02/20 11:32:45 ajk Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + // this is a useful shorthand + private static String encode(String s) { return ZTPCommand.encode(s); } + + public String home; + public Hashtable content = new Hashtable(); + public Hashtable cellswithspans = new Hashtable(); + public Hashtable dims = new Hashtable(); + public Hashtable stringscrolls = new Hashtable(); + + public SpaceDump(Reader reader) throws IOException { + BufferedReader r = new BufferedReader(reader); + + ZTPCommand com; + try { + com = new ZTPCommand(r.readLine()); + if (!com.name.toUpperCase().equals("H") || com.args.length != 3 + || !com.args[0].toUpperCase().equals("ZZSpaceDump".toUpperCase())) + throw new ZZError("This is not a space dump"); + + if (!com.args[1].equals("0")) + throw new ZZError("I don't know how to slurp this file"); + } catch (SyntaxError e) { + throw new ZZError("This is not a space dump (syntax error: + " + + e.getMessage() + ")"); + } + + home = com.args[2]; + + while (true) { + com = new ZTPCommand(r.readLine()); + + if (com.name.toUpperCase().equals("C")) { + if (com.args.length != 2) + throw new SyntaxError("wrong number of arguments for C"); + + content.put(com.args[0], com.args[1]); + cellswithspans.remove(com.args[0]); + } else if (com.name.toUpperCase().equals("R")) { + if (com.args.length < 3) + throw new SyntaxError("too few arguments to R"); + + if (!dims.containsKey(com.args[0])) { + dims.put(com.args[0], new Hashtable()); + } + + Hashtable dim = (Hashtable)dims.get(com.args[0]); + + for (int i = 1; i + 1 < com.args.length; i++) { + dim.put(com.args[i], com.args[i+1]); + } + } else if (com.name.toUpperCase().equals("SP")) { + if (com.args.length != 2) + throw new SyntaxError("wrong number of arguments to SP"); + + content.put(com.args[0], com.args[1]); + cellswithspans.put(com.args[0], com.args[0]); + } else if (com.name.toUpperCase().equals("SC")) { + if (com.args.length != 2) + throw new SyntaxError("wrong number of arguments to SC"); + + String scroll = (String)stringscrolls.get(com.args[0]); + if (scroll == null) scroll = ""; + scroll += com.args[1]; + stringscrolls.put(com.args[0], scroll); + } else if (com.name.toUpperCase().equals("F")) { + break; + } else { + throw new SyntaxError("unknown command"); + } + } + } + + /** Prints a dump of space to pw. */ + public static void dump(final PrintWriter pw, final ZZSpace space) { + pw.println("H ZZSpaceDump 0 " + encode(space.getHomeCell().getID())); + + Stack stack = new Stack(); + for (Enumeration e = space.cells(); e.hasMoreElements();) { + stack.push(e.nextElement()); + } + + String[] dims = space.dims(); + + Hashtable seen = new Hashtable(); + Hashtable scrolls = new Hashtable(); + while (!stack.empty()) { + ZZCell c = (ZZCell)stack.pop(); + seen.put(c, c); + p("processing cell " + c); + + Span s = c.getSpan(); + if (s == null) { + pw.println("C " + encode(c.getID()) + " " + encode(c.getText())); + } else { + scrolls.put(s.getStart().getScroll(space), ""); + scrolls.put(s.getEnd().getScroll(space), ""); + pw.println("SP " + encode(c.getID()) + " " + encode("" + s)); + } + + for (int i = 0; i < dims.length; i++) { + ZZCell d = c.s(dims[i]); + if (d != null) { + p("processing connection (" + dims[i] + ": " + c + " -> " + d); + if (!seen.containsKey(d)) stack.push(d); + pw.println("R " + encode(dims[i]) + " " + + encode(c.getID()) + " " + encode(d.getID())); + } + d = c.s(dims[i], -1); + if (d != null) p("processing connection (" + dims[i] + ": " + d + " -> " + c); + if (d != null && !seen.containsKey(d)) stack.push(d); + } + } + + for (Enumeration e = scrolls.keys(); e.hasMoreElements();) { + Scroll s = (Scroll)e.nextElement(); + if (!(s instanceof StringScroll)) { + ZZLogger.log("ignoring non-string scroll " + s.getId()); + continue; + } + StringScroll ss = (StringScroll)s; + final int ll = 50; + for (long i = 0; i < ss.curEnd(); i += ll) { + int l = (int)(ss.curEnd() - i < ll ? ss.curEnd() - i : ll); + pw.println("SC " + encode(ss.getId()) + " " + encode(ss.getString(i, l))); + } + } + pw.println("F"); + } +} diff --git a/Java/SysLogger.java b/Java/SysLogger.java new file mode 100644 index 0000000..135f2b2 --- /dev/null +++ b/Java/SysLogger.java @@ -0,0 +1,44 @@ +/* +SysLogger.java + * + * Copyright (c) 1999, 2000 Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag; + +class SysLogger { + + private static native void openlog(); + private static native void syslog(String msg, boolean verbose); + + public static synchronized void init() throws UnsatisfiedLinkError { + System.loadLibrary("gzigzag-syslog"); + openlog(); + } + + public static synchronized void log(String s) { + syslog(s, false); + } + + public static synchronized void verblog(String s) { + syslog(s, true); + } + +} diff --git a/Java/TODO b/Java/TODO new file mode 100644 index 0000000..61a9fdf --- /dev/null +++ b/Java/TODO @@ -0,0 +1,155 @@ +Currently, the up-to-date task list is at sourceforge.net's task manager for +gzigzag project. All the tasks below have not yet been added, but there are +several interesting tasks there already which are mostly more well-defined +and important than the ones below. + +If you want to work on any major task, please contact lukka@iki.fi first +to avoid overlapping work. The order below is random, not importance nor +a plan. + +The two MAJOR design questions: these are not easy to solve +since there are many issues here + +- 3rd generation file format: caching of saves to speed up operation + - the three features: + - micro-level undo + - cache saves + - use as notification buffer: check notifications all at once when + the code has finished. +- slices + - code complexity + - lazy loading + +Minor design questions: +- circulars: different ops for going over back to headcell? + -> right now too easy to lock up. + +Next major code cleanup: +- event queues, caching of some renderings? +- go through ZZCell, VStream and other APIs, check function names and parameters + for consistency. +- move packages +- document some APIs +- Redo ZZPrimitiveActions using clang as an intermediator. +- StringScroll -> interface! + +Ted's requests: +- g to home cell, G ctrl home cell +- m marks current cell, M ctrl + (m done, M not) +- flags: + - no splines + - continuous drawing i.e. show same cell more than once +- repeat bars +- viewspecs also visible +- 4th dim? +- search -> mark +- place for marks (system list) +- number up/down +- washcloth windows / iris windows + +Need more specs from Ted for: +- flob coordinate handling: zoom, setting etc. +- textcloud UI - two textclouds +- outline + expanded view using billowing +- vstream internal structure + markup + cursor handling when vstream + changed + +Jobs for Vesa: +- Make FileWritable cache things: + - cache writes until a non-contiguous one is made, or + a read is done. + - cache reads by a readahead + - use a fixed buffer of e.g. 256 or 512 bytes. + - make caching optional and timetest with and without + - be very surprised about the results ;) + + - MAKE SURE TO PUT AN EXPLICIT FLUSH COMMAND INTO WRITABLE AND + CALL IT AFTER EVERY FULL RECORD IS WRITTEN! + + (If you want justification for this, just try strace'ing + a run and see how many system calls are completely redundant) + +- MBox reader: make it structural, i.e. connect values of a field on + a d.byfield (sorted!), split multi-values into several cells and use clones for + the same people and msgids. +- undo +- move all AbstractView functionality to ZZDefaultSpace + --> think about the function names, propose better if you can. +- printing ? Export to html. +- Extern module for external commands + +AJK: +project infrastructure: +- a test build daemon using JDK not Jikes +- javadoc autobuild daemon? +development: +- WET raster, structure +- add an option to TreeRaster for showing less-deep cells as larger +- fix the billowing bug in TreeRaster + +Anyone: + +- Do an RFC (e.g. 822) in a REAL, proper hypertext fashion. + +- vstream -> enfilade-like thing + + paragraph jumping + +- tight brick links & edges with lighter color + +- allow changing direction associated with dimension +- allow changing priorities - joystick & other controls? + +- improve updatemanager and the views: + - updatemanager should take care of all animation lengths etc. + - there should be a parameter "complexity" which would allow + the updatemanager to tell a view to update itself only partially + (e.g. on animation on slow machines). + +- change ViewCell to Viewcell everywhere + XXX to viewspecs / ??? + +- put debug info configuration into structure!! + - all involved classes in structure. Really neat. + +- finish defaultspace + +- separation into a global zigzag interface and a gzigzag implementation + for a standard (e.g. DOM-like) API separation + +- grep the source for 'XXX' + +- create a singlecellraster that shows all the connections from the given + cell along dimensions on a given list. + +- check double clicks! If one click rerasters, what happens after? + +- better rasters + - e.g. headcell-based. + +- change dimensions to cells instead of strings. + - think about slicing problems... must handle when bringing + in the slice. + +- first personal space: BOOKMARKS + +- Clang + - primitive and advanced + +- slices + +- cursorspaces: d.cursor implemented transiently, to avoid lengthening + the cellscroll - + - possibly implement in ZZGlobal using FLAG_TRANSIENT cells? + +- a view of the filesystem as a ZZ space. + +- cellscrolls: The data is there but the access isn't + - animate through a cellscroll + - undo from cellscroll. + (XXX Not cellscroll but persistentdimspace now!) + +- an HTML page showing pictures and applets to introduce people to ZZ: + show an image of the space and then an applet where you can move through + that space. Start by just viewing, then allow people to change the space. + diff --git a/Java/TestSpace.java b/Java/TestSpace.java new file mode 100644 index 0000000..fd9742a --- /dev/null +++ b/Java/TestSpace.java @@ -0,0 +1,53 @@ +/* +TestSpace.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.io.*; + +public class TestSpace { + static void p(String s) { System.out.println(s); } + + static public void test(ZZSpace s) { + ZZCell c1 = s.getHomeCell(); + ZZCell c2 = c1.N("d.1", 1); + c2.setText("FOO"); + p("Id: "+c2.getID()); + p("Text: "+c2.getText()); + if(!("FOO".equals(c2.getText()))) + throw new ZZError("Not FOO"); + } + public static void main(String[] argv) { + // try { + File f = new File("/tmp/zzspacetest"+Math.random()); + p("File: "+f); + ZZSpace space = new ZZCacheDimSpace(new DirStreamSet(f)); + test(space); + // } catch(Exception e) { + // ZZLogger.exc(e); + // } + System.exit(0); + } +} + + + diff --git a/Java/TimeTest.java b/Java/TimeTest.java new file mode 100644 index 0000000..d3b6a11 --- /dev/null +++ b/Java/TimeTest.java @@ -0,0 +1,155 @@ +/* +TimeTest.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Miika Pekkarinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Miika Pekkarinen + * Rewritten by Tuomas Lukka + */ + +package org.gzigzag; + +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; + + +public class TimeTest { + static public abstract class Test { + public String name; + public abstract void test(ZZCell home, int nrounds); + } + + static Test newtest = new Test() { { name = "New"; } + public void test(ZZCell home, int nrounds) { + for(int i=0; i + * The operations are cleverly stored to minimize memory use: + * an array of Object refs, some of which are operations and after + * them their parameters. The parameters are not stored in the operation + * objects in order to avoid creating a new object instance per undoable + * operation. + *

    + * NOTE: this means that a parameter to an operation CANNOT IMPLEMENT + * UndoList.Op itself! That would break the chain. It would need to be + * e.g. wrapped into an array. + *

    + * So the orders are: undo in reverse, redo in original order and + * commit in reverse. + */ + +public class UndoList { +String rcsid = "$Id: UndoList.java,v 1.10 2000/10/26 18:09:29 tjl Exp $"; + public static boolean dbg = false; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + /** An undoable operation. + * Classes implementing this class can either be real + * operations or simply classes of operations that take + * their parameters from the Object array, in order + * to save space and use only one instance of the Op object. + * @see UndoList + * @see ZZCacheDimension + */ + public interface Op { + /** Undo the operation. + */ + void undo(Object[] list, int nth); + /** Redo the operation. + */ + void redo(Object[] list, int nth); + /** Commit the operation. + * The operation need not be undoable after a commit. + */ + void commit(Object[] list, int nth); + } + + Object[] ops = new Object[2000]; + int nops = 0; + + int stamp0; + + int[] stamps = new int[64]; + int nstamps = 0; + + int nundoes = 0; + + UndoList(int inittime) { + stamp0 = inittime; + makeStampRoom(1); + stamps[nstamps++] = 0; + } + + /** Place a timestamp into the operation list. + * Undo and redo work on stamped boundaries. + * If no operations since last stamp, returns last stamp. + */ + public int stamp() { + p("STAMP!"); + if(nundoes != 0) return -1; + if(stamps[nstamps-1] == nops) + return stamp0 + nstamps-1; + makeStampRoom(1); + stamps[nstamps++] = nops; + return stamp0 + nstamps-1; + } + + /** Commit the changes up to the present. + * Returns the new timestamp. + */ + public int commit() { + finalizeUndo(); + + int stampno = stamp(); + for(int i=nops-1; i>=0; i--) { + if(ops[i] instanceof Op) + ((Op)ops[i]).commit(ops, i); + } + + nops = 0; + nstamps = 0; + nundoes = 0; + stamp0 = stampno; + stamps[nstamps++] = 0; + return stampno; + } + + /** Undo operations until the previous timestamp, if possible. + * After committing, undo won't work until you stamp again. + */ + public void undo() { + try { + int curop = stamps[nstamps-1 - nundoes]; + p("Undo: "+curop+" "+nstamps+" "+nundoes); + // Nothing to do. + if(curop == 0) { + ZZLogger.log("Can't undo further"); + return; + } + int prevop = stamps[nstamps-1 - nundoes - 1]; + for(int i = curop - 1; i >= prevop; i--) { + if(ops[i] instanceof Op) { + p("Undo: "+i+" "+ops[i]); + ((Op)ops[i]).undo(ops, i); + } + } + nundoes += 1; + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZFatalError("Exception while undoing"); + } + } + + /** Redo operations until the next timestamp, after undo has been + * used. Any changes meanwhile make this impossible (branches later??). + */ + public void redo() { + if(nundoes <= 0) { + ZZLogger.log("Nothing to redo"); + return; + } + try { + int curop = stamps[nstamps-1 - nundoes]; + int nextop = stamps[nstamps-1 - nundoes + 1]; + for(int i = curop; i < nextop; i++) { + if(ops[i] instanceof Op) { + p("Undo op: "+i); + ((Op)ops[i]).redo(ops, i); + } + } + nundoes -= 1; + } catch(Exception e) { + throw new ZZFatalError("Exception while undoing"); + } + + } + + /** Finalize the undo: the system will not be able to redo changes + * that happened after this. + */ + public void finalizeUndo() { + if(nundoes == 0) return; + p("FINALIZE UNDO! "+nundoes); + nops = stamps[nstamps-1 - nundoes]; + nstamps -= nundoes; + nundoes = 0; + } + + protected final void makeRoom(int n) { + if(nops + n >= ops.length) { + Object[] opsnew = new Object[ops.length * 2]; + System.arraycopy(ops, 0, opsnew, 0, nops); + ops = opsnew; + } + } + + protected final void makeStampRoom(int n) { + if(nstamps + n >= stamps.length) { + int[] stampsnew = new int[stamps.length * 2]; + System.arraycopy(stamps, 0, stampsnew, 0, nstamps); + stamps = stampsnew; + } + } + + public void add(Op o1, Object o2, Object o3) { + if(nundoes != 0) finalizeUndo(); + makeRoom(3); + int i = nops; + ops[nops++] = o1; + ops[nops++] = o2; + ops[nops++] = o3; + p("Add 3op: "+i+" "+o1+" "+o2+" "+o3); + } + public void add(Op o1, Object o2, Object o3, Object o4) { + if(nundoes != 0) finalizeUndo(); + makeRoom(3); + int i = nops; + ops[nops++] = o1; + ops[nops++] = o2; + ops[nops++] = o3; + ops[nops++] = o4; + p("Add 4op: "+i+" "+o1+" "+o2+" "+o3+" "+o4); + } + +} diff --git a/Java/ZOb.java b/Java/ZOb.java new file mode 100644 index 0000000..322d726 --- /dev/null +++ b/Java/ZOb.java @@ -0,0 +1,39 @@ +/* +ZOb.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; + +/** An object whose data is read from the structure. + * This is an interface implemented by all the objects generated from + * .zob files by zob2java.pl. + */ + +public interface ZOb { + /** Read the parameters for this ZOb. + * Returns a string describing the errors encountered, or null if + * everything went fine.. + */ + String readParams(ZZCell c); +} + diff --git a/Java/ZTPCommand.java b/Java/ZTPCommand.java new file mode 100644 index 0000000..ab415c5 --- /dev/null +++ b/Java/ZTPCommand.java @@ -0,0 +1,207 @@ +/* +ZTPCommand.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag; +import java.util.*; + +/** ZTP command parser. After instance construction, the attribute + * "name" contains the command name and the attribute "args" contains + * the arguments of the command. Since this class is also used in the + * conversion space dumper, it is in the main package instead of the + * ztp package. */ +public class ZTPCommand { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + public String name; + public String[] args; + + public static class RV { + public String token; + public String rest; + public RV(String token, String rest) { + this.token = token; + this.rest = rest; + } + public String toString() { + return "[token: " + token + " | rest: " + rest + "]"; + } + } + + public static RV lwsp(String str) { + int i; + for (i = 0; i < str.length(); i++) { + if (str.charAt(i) != 9 && str.charAt(i) != 32) break; + } + return new RV(str.substring(0, i), str.substring(i)); + } + + public static boolean ASCII_word_char(char c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || c == '/'; + } + + public static RV ASCII_word(String line) { + int rlen = 0; + for (int i = 0; i < line.length(); i++) { + char c = line.charAt(i); + if (!ASCII_word_char(c)) break; + ++rlen; + } + if (rlen == 0) return null; + return new RV(line.substring(0, rlen), line.substring(rlen)); + } + + public static boolean ASCII_num_char(char c) { + return '0' <= c && c <= '9'; + } + + public static RV ASCII_number(String line) { + int rlen = 0; + for (int i = 0; i < line.length(); i++) { + char c = line.charAt(i); + if (!ASCII_num_char(c)) break; + ++rlen; + } + if (rlen == 0) return null; + return new RV(line.substring(0, rlen), line.substring(rlen)); + } + + public static RV quoted_string(String line) { + if (line.charAt(0) != 34) return null; + String rv = ""; + int i; + boolean ok = false; + for (i = 1; i < line.length(); i++) { + char c = line.charAt(i); + if (c == '"') { + if (i + 1 < line.length() && line.charAt(i+1) == '"') { + ++i; + } else { + ok = true; + break; + } + } + if (c == '\\') { + if (i + 1 == line.length()) { + throw new SyntaxError("unterminated escape sequence"); + } + if (line.charAt(i+1) == '\\' || line.charAt(i+1) == '"') { + c = line.charAt(++i); + } else if (line.charAt(i+1) == 'n') { + c = '\n'; + ++i; + } else { + throw new SyntaxError("invalid escape sequence"); + } + } + rv += c; + } + if (!ok) { + throw new SyntaxError("unterminated quoted string"); + } + return new RV(rv, line.substring(i+1)); + } + + private static String encode_quoted(String s) { + String rv = "\""; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '"') { + rv += "\"\""; + } else if (s.charAt(i) == '\\') { + rv += "\\\\"; + } else if (s.charAt(i) == '\n') { + rv += "\\n"; + } else { + rv += s.charAt(i); + } + } + rv += "\""; + return rv; + } + + /** Encodes s as one token for the Command parser. */ + public static String encode(String s) { + if (s.length() == 0) return "\"\""; + if (ASCII_num_char(s.charAt(0))) { + for (int i = 1; i < s.length(); i++) { + if (!ASCII_num_char(s.charAt(i))) { + return encode_quoted(s); + } + } + return s; + } + if (ASCII_word_char(s.charAt(0))) { + for (int i = 1; i < s.length(); i++) { + if (!ASCII_word_char(s.charAt(i))) { + return encode_quoted(s); + } + } + return s; + } + return encode_quoted(s); + } + + public ZTPCommand(String line) { + RV rv; + + rv = ASCII_word(line); + if (rv == null) throw new SyntaxError("error parsing command name"); + name = rv.token; + line = lwsp(rv.rest).rest; + Vector v = new Vector(); + while (line.length() > 0 && !line.equals("\n") + && !line.equals("\r") && !line.equals("\r\n")) { + p("line = " + line); + rv = quoted_string(line); + if (rv != null) { + p("arg parsed as a quoted string, token = " + rv.token); + } else { + rv = ASCII_word(line); + if (rv != null) { + p("arg parsed as an ASCII word, token = " + rv.token); + } else { + rv = ASCII_number(line); + if (rv != null) { + p("arg parsed as an ASCII number, token = " + rv.token); + } else { + throw new SyntaxError("error parsing command arguments"); + } + } + } + v.addElement(rv.token); + line = lwsp(rv.rest).rest; + } + args = new String[v.size()]; + for (int i = 0; i < args.length; i++) { + args[i] = (String)v.elementAt(i); + } + p("args.length = " + args.length); + } + + public String toString() { + String rv = name; + for (int i = 0; i < args.length; i++) { + rv += "_" + args[i]; + } + return rv; + } +} + diff --git a/Java/ZZCanvasView.java b/Java/ZZCanvasView.java new file mode 100644 index 0000000..7586f11 --- /dev/null +++ b/Java/ZZCanvasView.java @@ -0,0 +1,231 @@ +/* +ZZCanvasView.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.event.*; +import java.awt.*; + +/** A view which creates 2-D canvases to show. + */ + +public class ZZCanvasView extends ZZViewComponent { +public static final String rcsid = "$Id: ZZCanvasView.java,v 1.35.2.1 2001/04/08 13:00:57 bfallenstein Exp $"; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + public ZZCanvasView() { + super(); + } + + public void setViewcell(ZZCell v0) { + super.setViewcell(v0); + } + + final void upd(InputEvent ev) { + p("Upd "+this); + ZZUpdateManager.setFast(this); + ZZUpdateManager.freeze(); + try { + kb.perform(ev, this, ctrlView, curcanv); + ev.consume(); + ZZObsTrigger.runObsQueue(); + } finally { + ZZUpdateManager.thaw(); + } + p("Upd finished "+this); + } + + public void mouseClicked(MouseEvent e) { + p("Mouse clicked "+ e); + upd(e); + // super.mouseClicked(e); + } + public void mousePressed(MouseEvent e) { + p("MousePressed " + e); + // clicked = curcanv.getclicked(e.getX(), e.getY()); + upd(e); + } + public void mouseDragged(MouseEvent e) { + p("MouseDragged " + e); + upd(e); + } + public void mouseReleased(MouseEvent e) { + p("MouseReleased " + e); + upd(e); + } + boolean xored = false; + int prevx; int prevy; Object prevob; + public void mouseMoved(MouseEvent e) { + if ( curcanv == null ) return; + Graphics g = getGraphics(); + Object ob = curcanv.getObjectAt(e.getX(), e.getY()); + // If there was a previous XOR cursor, wipe it out. + if(xored) { + if(ob != null && ob.equals(prevob)) { + prevx = e.getX(); + prevy = e.getY(); + return; + } + curcanv.renderXOR(g, prevx, prevy); + } + prevx = e.getX(); + prevy = e.getY(); + prevob = ob; + // This simply allows the canvas to show which element would get + // activated (such as where the insertion cursor would be placed) + // by a mouse click. + + curcanv.renderXOR(g, prevx, prevy); + xored = true; + super.mouseMoved(e); + } + + ZZScene oldcanv; + long oldtime; + ZZScene curcanv; + ZZCell cursor; + + String[]dims; + + public boolean reraster() { + p("reraster " + this); + try { + dims = ZZDefaultSpace.getDimList(viewCell); + cursor = ZZCursorReal.get(viewCell); + if(cursor == null) { + validraster = false; + p("No cursor"); + return false; + } + + Dimension d = getSize(); + + // XXX ??? + /* if(oldcanv == null) */ + oldcanv = curcanv; + + curcanv = ZZDefaultSpace.getScene(viewCell, this); + validraster = true; + + p("Reraster returning"); + return (oldcanv != null && oldcanv.isInterpUseful(curcanv)); + } catch(Exception e) { + ZZLogger.exc(e, "Exception while rastering"); + validraster = false; + oldcanv = curcanv = null; + return false; + } catch(ZZError e) { + ZZLogger.exc(e, "ZZError while rastering"); + validraster = false; + oldcanv = curcanv = null; + return false; + } + } + + public void paintInto(Graphics gr) { + // p("DOPAINT " + this + " " + parentView + " " + + // needreraster + " " + validraster +" " + animate ); + synchronized(viewCell.getSpace()) { + if(fract >= 1.0) oldcanv = null; + if(!validraster) { + reraster(); + if(!validraster) { + gr.setColor(Color.red); + gr.setFont(new Font("SansSerif", Font.BOLD, 30)); + gr.drawString("RASTER ERROR", 0, getSize().height/2); + System.out.println("Not valid raster"); + repaint(1000); + } + return; + } + /* + if(needreraster) { + needreraster = false; + re_raster(); + } + */ + // p("DOPAINT: AFTER RERASTER: "+parentView+" "+validraster); + /* + if(!validraster) { + needreraster = true; + repaint(1000); + return; + } + */ + // if(parentView!=null) { + // curcanv.dbgPrint(); + // } + // super.paint(gr); + // paintBorder(gr); + Dimension thisd = getSize(); + Color bg = getBackground(); + ZZCell modec = ZZKeyBindings1.getMode(viewCell).s("d.color"); + if(modec != null) { + if(modec.getText().equals("CURSOR")) + bg = ZZCursorReal.getColorOrWhite(viewCell); + else + bg = new java.awt.Color(Integer.parseInt(modec.getText())); + } + gr.setColor(bg); + Insets ins = getInsets(); + gr.fillRect(ins.left, ins.top, + thisd.width-ins.left-ins.right, + thisd.height-ins.top-ins.bottom); + gr.setColor(Color.black); + + // System.out.println(t+" "+oldtime); + if(fract < 1 && oldcanv != null) { + if(fract > 0.3) { + curcanv.renderInterp(gr, oldcanv, 1-fract); + } else { + oldcanv.renderInterp(gr, curcanv, fract); + } + + getToolkit().sync(); + // repaint(); + } else { + curcanv.render(gr); + + // XXX THIS CODE SHOULDN'T BE HERE! + // IT SHOULD BE SPECIFIED IN THE STRUCTURE + // FOR EACH VIEW SEPARATELY IF DESIRED + String s = ZZDefaultSpace.getInbuf(viewCell.getSpace(), + false); + if(s != null) { + if(s.equals("")) + s = ZZCursorReal.get(viewCell).getID(); + Dimension d = getSize(); + gr.drawString(s, 10, d.height-20); + } + + getToolkit().sync(); + } + if(xored) { + curcanv.renderXOR(gr, prevx, prevy); + // XXX get this right during interpolation + } + } + // p("DOPAINTRET " + this + " " + needreraster + " " + animate ); + wasInPaint = true; + } + +} diff --git a/Java/ZZCell.java b/Java/ZZCell.java new file mode 100644 index 0000000..f8f54d5 --- /dev/null +++ b/Java/ZZCell.java @@ -0,0 +1,719 @@ +/* +ZZCell.java + * + * Copyright (c) 1999-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +/* + * Well, he'd been in enough cells. There were ways to handle these + * things. The important thing was to be direct. He got up and banged + * on the bars until the warder sauntered along the corridor. + * `Yes, mate?' + * `I just want to get things sorted out,' said Rincewind. `It's + * not as though I've got time to waste, okay?' + * `Yep?' + * `Is there any chance that you're going to fall asleep + * in a chair opposite this cell with your keys fully exposed on a table + * in front of you?' + * - Terry Pratchett, The Last Continent, p.267 + */ +package org.gzigzag; +import java.util.*; + +/** An abstract class to represent a ZigZag cell. + *

    + * There is no unique cell to Java object mapping, so there may be + * several equivalent Java objects representing the same cell. + * Use the equals method for comparisons. + */ + +public abstract class ZZCell { +public static final String rcsid = "$Id: ZZCell.java,v 1.76 2001/02/08 11:18:39 ajk Exp $"; + + /** Obtain the unique ID for this cell. + * Note that this method may throw an exception + * if the space this cell is in does not support cell IDs. + */ + public String getID() { + throw new NullPointerException("This cell type has no IDs!"); + } + + /** Create a new cell connected to this cell. + * @param dim Dimension to create the cell along + * @param dir The direction, either positive or negative + */ + public final ZZCell N(String dim, int dir) { + return N(dim, dir, null, 0); + } + public final ZZCell N(String dim) { + return N(dim, 1, null, 0); + } + + /** Get a new cell associated with this cell (ie.same slice) + */ + public abstract ZZCell N(); + + /** Get or create a new cell connected to this cell. + * A convenience function which first tries to use getNeighbour + * and if that returns null, creates a new neighbour. + * @param dim Dimension to create the cell along + * @param dir The direction, either positive or negative + * @param obs The observer + */ + public ZZCell getOrNewCell(String dim, int dir, ZZObs o) { + ZZCell r; + if((r = s(dim, dir, o)) != null) return r; + return N(dim, dir, o); + } + public ZZCell getOrNewCell(String dim, int dir) { + return getOrNewCell(dim, dir, null); + } + public ZZCell getOrNewCell(String dim) { + return getOrNewCell(dim, 1, null); + } + /** Create a new cell connected to this cell and attach an observer + * to it + * atomically. + * @param dim Dimension to create the cell along + * @param dir The direction, either positive or negative + * @param obs The observer + */ + public final ZZCell N(String dim, int dir, ZZObs o) { + return N(dim, dir, o, 0); + } + /** Create a new cell connected to this cell + * to it + * atomically. + * @param dim Dimension to create the cell along + * @param dir The direction, either positive or negative + * @param flags The flags to guide the type of the new cell + */ + public final ZZCell N(String dim, int dir, long flags) { + return N(dim, dir, null, flags); + } + /** Create a new cell connected to this cell and attach an observer + * to the connection + * atomically. + *

    + * NOTE: this routine MUST insert the cell, not just blindly + * delete the former connection. + * @param dim Dimension to create the cell along + * @param dir The direction, either positive or negative + * @param obs The observer + * @param flags The flags to guide the type of the new cell + */ + public abstract ZZCell N(String dim, int dir, ZZObs o, long flags); + + + /** Delete this cell. */ + public abstract void delete(); + /** Delete this cell from a rank along a dimension. */ + public void excise(String dim) { + synchronized(getSpace()) { + ZZCell cm = s(dim, -1); + ZZCell cp = s(dim, 1); + if(cm!=null && cp!=null) { + cm.disconnect(dim, 1); + cp.disconnect(dim, -1); + cm.connect(dim, cp); + } + else if(cm!=null) + cm.disconnect(dim, 1); + else if(cp!=null) + cp.disconnect(dim, -1); + } + } + /** Connect this cell to another along a dimension. + * If there is a former connection, + * a ZZConnectWouldBreakError is thrown. + * @param dim Dimension to connect along + * @param to Cell to connect to. This cell will end up poswards from us. + */ + public abstract void connect(String dim, ZZCell to); + /** Connect this cell to another along a dimension in a specified + * direction. + * If there is a former connection, + * a ZZConnectWouldBreakError is thrown. + * @param dim Dimension to connect along + * @param dir The direction, either positive or negative + * @param to Cell to connect to. + */ + public void connect(String dim, int dir, ZZCell to) { + if(dir > 0) { + connect(dim, to); + } else { + to.connect(dim, this); + } + } + + /** Insert a cell next to this one in the rank. + * Both connections of the what cell along the specified dimension are + * deleted before inserting it. + * @param dim Dimension to connect along + * @param dir The direction, either positive or negative + * @param what Cell to insert + */ + public abstract void insert(String dim, int dir, ZZCell what); + + /** Disconnect a connection from this cell. + * @param dim Dimension to disconnect along + * @param dir The direction, either positive or negative + */ + public abstract void disconnect(String dim, int dir); + + /** Set the text contained in the cell. + * @param text The new text + */ + public abstract void setText(String text); + + /** Set the text contained in the cell to a pointer. + * @param text The new text, as a span pointing to a stable scroll + */ + public abstract void setSpan(Span text); + + /** Get a reference to the ZZSpace object describing the whole space */ + public abstract ZZSpace getSpace(); + + /** Find the neighbour of this cell along a dimension + * attach an observer to this relation + * atomically. + * @param dim Dimension to go along + * @param dir The direction, either positive or negative + * @param obs The observer + * @return The neighbour, or null if none. + */ + public abstract ZZCell s(String dim, int dir, ZZObs o); + + /** Find the neighbour of this cell along a dimension. + * atomically. + * @param dim Dimension to go along + * @param dir The direction, either positive or negative + * @return The neighbour, or null if none. + */ + public ZZCell s(String dim, int dir) { + return s(dim,dir,null); + } + + /** Find the next cell along a dimension. + * Always moves poswards. + * @param dim Dimension to go along + * @return The neighbour, or null if none. + */ + public ZZCell s(String dim) { + return s(dim,1,null); + } + + /** Find the headcell of a rank. + * XXX The default implementation does not handle circular ranks correctly! + * @param dim Dimension to go along + * @param dir The direction, either positive or negative + * @return The headcell + */ + public ZZCell h(String dim, int dir) { + return h(dim, dir, false, null); + } + public ZZCell h(String dim, int dir, ZZObs o) { + return h(dim, dir, false, o); + } + public ZZCell h(String dim, boolean ensuremove) { + return h(dim, -1, ensuremove, null); + } + public ZZCell h(String dim, int dir, boolean ensuremove) { + return h(dim, dir, ensuremove, null); + } + /** Find the headcell of a rank. + * The headcell is the most negative cell so this call is equivalent + * to h(dim, -1). + */ + public ZZCell h(String dim) { + return h(dim, -1, false, null); + } + + /** Find the headcell of a rank. + * XXX The default implementation does not handle circular ranks correctly! + * HOWEVER, all code must be prepared for this function to return a cell + * that is just some cell in a looping rank. This means that a while loop + * looking for null going poswards from the headcell might be infinite + * and needs the user to explicitly detect loops. + * Just in case of synch problems, it is recommended that the user check + * both for equality to the headcell and use a + * LoopDetector, in case the loop changed. + * @param dim Dimension to go along + * @param dir The direction, either positive or negative + * @return The headcell + */ + public abstract ZZCell h(String dim, int dir, boolean ensuremove, + ZZObs o); + + + /** Count the length of the rank. + * @param dim Dimension to go along + * @return length of the rank. + */ + public int getRankLength(String dim) { + ZZCell cur = this; + ZZCell next; + int i = 0; + while((next=cur.s(dim,1))!=null) { + + if(next == this) + throw new ZZInfiniteLoop("CIRCULAR HEAD"); + cur = next; + i++; + } + cur = this; + while((next=cur.s(dim,-1))!=null) { + + if(next == this) + throw new ZZInfiniteLoop("CIRCULAR HEAD"); + cur = next; + i++; + } + return i+1; + } + + + /** Find the next intersection of two ranks. + * XXX The default implementation does not handle circular ranks correctly! + * @param dim Dimension to go along from this cell + * @param dir The direction, either positive or negative, from this cell + * @param cell2 The other cell + * @param dim2 Dimension to go along from the other cell + * @param dir2 The direction, either positive or negative, from the other cell + */ + public ZZCell intersect(String dim, int dir, ZZCell cell2, String dim2, int dir2) { + synchronized(getSpace()) { + // If we knew how to find the shorter one... + Hashtable h = new Hashtable(); + ZZCell cur = this.s(dim,dir); + while(cur!=null) { + h.put(cur,cur); + cur = cur.s(dim,dir); + } + cur = cell2.s(dim2,dir2); + while(cur!=null) { + if(h.get(cur) != null) { + return cur; + } + cur = cur.s(dim2,dir2); + } + return null; + } + } + + /** Find all intersections of two ranks. + * XXX The default implementation does not handle circular ranks correctly! + * @param dim Dimension to go along from this cell + * @param dir The direction, either positive or negative, from this cell + * @param cell2 The other cell + * @param dim2 Dimension to go along from the other cell + * @param dir2 The direction, either positive or negative, from the other cell + */ + public ZZCell[] intersectAll(String dim, int dir, ZZCell cell2, String dim2, int dir2) { + synchronized(getSpace()) { + // If we knew how to find the shorter one... + Hashtable h = new Hashtable(); + ZZCell cur = this.s(dim,dir); + while(cur!=null) { + h.put(cur,cur); + cur = cur.s(dim,dir); + } + Vector v = new Vector(); + cur = cell2.s(dim2,dir2); + while(cur!=null) { + if(h.get(cur) != null) { + v.addElement(cur); + } + cur = cur.s(dim2,dir2); + } + ZZCell[] r = new ZZCell[v.size()]; + for(int i=0; i + * Is this the correct implementation? + */ + public String getGlobalID() { + if (getID().indexOf("@") != -1) return getID(); + return getID()+"@"+getSpace().getID(); + } + + /** Find a cell with the given contents. + */ + public ZZCell findText(String dim, int dir, String txt) { + return findText(dim, dir, txt, null); + } + public ZZCell findText(String dim, int dir, String txt, ZZObs o) { + ZZCell cur = s(dim, dir); + while(cur!=null && cur!=this && !cur.getText(o).equals(txt)) { + cur = cur.s(dim,dir,o); + } + if(cur==this) return null; + return cur; + } + + /** Whether another cell is on the given rank in the given dir. + */ + public boolean findCell(String dim, int dir, ZZCell c) { + if(this.equals(c)) return true; + ZZCell i = this.s(dim, dir); + while(i != null && !i.equals(c) && !i.equals(this)) i = i.s(dim, dir); + if(i==null) return false; + return i.equals(c); + } + + + public ZZCell getHomeCell() { + return getSpace().getHomeCell(); + } + + + public ZZCell zzclone() { + return getHeadcell("d.clone", 1).newCell("d.clone", 1); + } + + public ZZCell getRootclone() { + return getHeadcell("d.clone", -1); + } + + // This may become the new API of choice.. + public final String t() { return getText(); } + + /** Return a stringized form of this cell. + * This form is unstable and its use for anything except + * human-readable debugging is not recommended. + * Currently the format is: The cell ID in single quotes + * and the text content after that, in parentheses, + * for example '53' (Text in cell). + */ + public String toString() { + return "'"+getID() + "' (" + getText() + ")"; + } + + + /** Enumerate a (semi)rank. + * @param dim The dimension along which the (semi)rank is to be enumerated. + * @return An enumeration of all cells starting from this cell + * along dim in positive direction. + */ + public Enumeration enumRank(String dim) { + return enumRank(dim, 1); + } + + /** Enumerate a (semi)rank. + * @param dim The dimension along which the (semi)rank is to be enumerated. + * @param dir The direction along dim to enumerate. + * @return An enumeration of all cells starting from this cell + * along dim in direction dir. + */ + public Enumeration enumRank(String dim, int dir) { + class RankEnumeration implements Enumeration { + ZZCell c; + String dimension; + int direction; + public RankEnumeration(ZZCell c, String dimension, int direction) { + this.c = c; + this.dimension = dimension; + this.direction = direction; + } + public boolean hasMoreElements() { + return c != null; + } + + public Object nextElement() { + if (!hasMoreElements()) throw new NoSuchElementException(""); + ZZCell r = c; + c = c.s(dimension, direction); + return r; + } + }; + return new RankEnumeration(this, dim, dir); + } + + // Deprecated, old versions of the calls + + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell newCell(String dim, int dir, long flags) { + return N(dim, dir, flags); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell newCell(String dim, int dir, ZZObs o) { + return N(dim, dir, o); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell newCell(String dim, int dir) { + return N(dim, dir); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell newCell() { + return N(); + } + + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getNeighbour(String dim, int dir, ZZObs o) { + return s(dim, dir, o); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getNeighbour(String dim, int dir) { + return s(dim, dir); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getSteps(String dim, int dir, ZZObs o) { + return s(dim, dir, o); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getSteps(String dim, int dir) { + return s(dim, dir); + } + + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getHeadcell(String dim, int dir, boolean ensuremove, + ZZObs o) { + return h(dim, dir, ensuremove, o); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getHeadcell(String dim, int dir) { + return h(dim, dir); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getHeadcell(String dim, int dir, ZZObs o) { + return h(dim, dir, o); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getHeadcell(String dim, int dir, boolean ensuremove) { + return h(dim, dir, ensuremove); + } + /** Deprecated. + * @deprecated Use the new one-letter functions instead. + */ + public final ZZCell getHeadcell(String dim) { + return h(dim); + } + + + // Deprecated stuff. + + /** A flag passed to newCell meaning that the cell should not be stored + * persistently. This may enable some optimizations and + * save some persistent and/or temporary memory space. + * For example, cells that track which cells are shown in a view + * through a raster should probably be transient. + *

    + * Note that not all spaces support transient cells so this is + * only a hint in that context. In getFlags, the meaning is real. + * @deprecated Usefulness being evaluated + */ + long FLAG_TRANSIENT = 0x00000001; + /** A flag meaning that the text stored in this cell is + * an address. + * The method getText() will automatically + * return the text stored in the cell, whether it is just text + * or a span of text from a permascroll. + * If you want the span, use + * getSpan(). + * For users, a much better way to tell whether a cell is a span is + * simply

     c.getSpan() != null 
    . + * @deprecated Usefulness being evaluated + */ + long FLAG_ADDRESS = 0x00000002; + /** A flag meaning that the current cell is used only as a label. + * XXX Think about it a bit more - which operations shall it affect? + * @deprecated Usefulness being evaluated + */ + long FLAG_LABEL = 0x00000004; + + /** Get the flags associated with this cell. + * @deprecated Usefulness being evaluated + */ + public long getFlags() { return 0; } + /** Set the flags associated with this cell. + * @deprecated Usefulness being evaluated + */ + public void setFlags( long s, long u ) { } + +} + diff --git a/Java/ZZCellHandle.java b/Java/ZZCellHandle.java new file mode 100644 index 0000000..037181b --- /dev/null +++ b/Java/ZZCellHandle.java @@ -0,0 +1,81 @@ +/* +ZZCellHandle.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; + +/** A ZigZag cell, as a handle. + * This is a structure that is a handle to one cell. + * All handles to the same cell should be equal to each other. + * This means that the information contained within is only allowed + * to depend on the cell ID. + *

    + * The parts marked EXPERIMENTAL are such, and are subject to change. + * Those parts are related to implementing virtual subparts of spaces. + * The idea is to keep an Object handy that represents in a more simple + * form what this cell actually is in that subpart. + * Whether this is a speedup or a slowdown remains to be seen. + */ + +public abstract class ZZCellHandle extends ZZCell { +public static final String rcsid = "$Id: ZZCellHandle.java,v 1.5 2001/02/23 08:33:37 ajk Exp $"; + + /** The cell id. + */ + public final String id; + + /** EXPERIMENTAL: the part of the space that this cell is in. + */ + public final ZZSpacePart part; + + /** EXPERIMENTAL: the parsed ID (as provided by the space part) + * of this cell. + * This is supposed to be simply an easier-to-use representation + * of the ID string for the spacepart's dimensions to use. + * For instance, if the spacepart is a matrix, then parsedID could + * be a java.awt.Point -like object that contains the coordinates + * parsed out. + */ + public final Object parsedID; + + public ZZCellHandle(String id, ZZSpacePart part, Object parsedID) { + //if (id == null) throw new NullPointerException(); + this.id = id; + this.part = part; + this.parsedID = parsedID; + } + + public String getID() { + return id; + } + + public boolean equals(Object o) { + if(this == o) return true; + if(!(o instanceof ZZCellHandle)) return false; + ZZCellHandle it = (ZZCellHandle) o; + return id == it.id || id.equals(it.id); + } + + public int hashCode() { + return id.hashCode(); + } +} + diff --git a/Java/ZZCommand.java b/Java/ZZCommand.java new file mode 100644 index 0000000..03c8879 --- /dev/null +++ b/Java/ZZCommand.java @@ -0,0 +1,84 @@ +/* +ZZCommand.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; + +/** An abstract class representing a command stored in zz space. + * This should be thought of as a possible successor for ZZExec. Other than + * ZZExec, the object created is not a scripting engine, but rather a + * command which can be executed with a scripting engine. Subclasses of + * ZZCommand are expected to implement ZOb. + *

    + * This class also provides the static method getCommand, which returns the + * ZZCommand associated with a cell, if any. + */ + +public abstract class ZZCommand { + /** Execute some code as a callback from the user interface. + * This is a special execution context which is triggered through user + * action on a user interface. Note that some of the params + * are redundant and only provided for ease. All the other parameters + * can be deduced from view, ctrlview and clicked. + * @param view View where command executed + * @param cview Control view of view where command executed + * @param key The key the user pressed, as string, if any + * @param pt The point the user clicked on, if any + * @param xi The extra object - to get what was clicked, if any + */ + public void execCallback( + ZZCell target, + ZZView view, + ZZView cview, + String key, + Point pt, + ZZScene xi + ) { + exec(target); + } + + // /** Execute with parameters. + // * XXX Needs rethinking of the arguments. + // */ + // public abstract void exec(ZZCell[] params); + + /** Execute with a single parameter. + * An intermediate for calls which don't come from the UI, but from + * somewhere else (e.g., a trigger). + *

    + * Note that UI callbacks are proxied to exec by standard (that is, if + * execCallback isn't overridden.) + */ + public abstract void exec(ZZCell param); + + public static ZZCommand getCommand(ZZCell code) { + // Check if it's a ZOb first: + if(code.s("d.clone", -1) == null && + code.s("d.1", 1) == null) + return null; + ZOb z = ZZDefaultSpace.readZOb(code); + if(z != null && z instanceof ZZCommand) + return (ZZCommand) z; + return null; + } +} diff --git a/Java/ZZConnection.java b/Java/ZZConnection.java new file mode 100644 index 0000000..211c1ba --- /dev/null +++ b/Java/ZZConnection.java @@ -0,0 +1,62 @@ +/* +ZZConnection.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ + +package org.gzigzag; +/** A simple class defining a data type for connections in a ZZ space. + * Note, that nothing says a connection represented by a ZZConnection + * object should exist. (You can test it with exists() method). + * @see org.gzigzag.ZZCell#getConns() + */ +public class ZZConnection { + /** The start cell */ + public ZZCell c1; + /** The dimension the connection goes along */ + public String dim; + /** The direction of the connection */ + public int dir; + /** The end cell */ + public ZZCell c2; + public ZZConnection() { + } + /** Creates an object representing a link in ZZ space. + * @param c1 The first cell + * @param c2 The second cell + * @param dim The dimension of the connection + * @param dir The direction of the connection + */ + public ZZConnection(ZZCell c1, String dim, int dir, ZZCell c2) { + this.c1 = c1; + this.dim = dim; + this.dir = dir; + this.c2 = c2; + } + + /** Tests whether this connection exists in it's space. */ + public boolean exists() { + if(c1!=null && c2!=null && dim!=null && (dir==1||dir==-1) + && c1.s(dim, dir)==c2) + return true; + else + return false; + + } +} + diff --git a/Java/ZZCursor.java b/Java/ZZCursor.java new file mode 100644 index 0000000..e230224 --- /dev/null +++ b/Java/ZZCursor.java @@ -0,0 +1,70 @@ +/* +ZZCursor.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A thing that points to a cell or to an offset at a cell. + * It is possible to have read-only ZZCursor objects which will + * throw Errors for the modification attempts. + */ + +public abstract class ZZCursor { +String rcsid = "$Id: ZZCursor.java,v 1.7 2000/11/25 00:36:33 tjl Exp $"; + /** Get the cell the cursor is pointing to. + */ + public abstract ZZCell get(); + /** Set the cursor to point to a cell. + */ + public abstract void set(ZZCell c); + /** Get the offset of this cursor. + */ + public abstract int getOffs(); + /** Set the offset of this cursor. + */ + public abstract void setOffs(int i); + + + /** Set the cursor and offset to the given cursor. + */ + public void set(ZZCursor c) { + set(c.get()); + setOffs(c.getOffs()); + } + + /** The constant to specify that there is no offset + * for this cursor. + */ + static public final int NO_OFFSET = -100; + + public boolean equals(Object o) { + if(this == o) return true; + if(!(o instanceof ZZCursor)) return false; + ZZCursor oth = (ZZCursor) o; + return (oth.get() == get() && oth.getOffs() == getOffs()); + } + + public String toString() { + return "CURS: "+getOffs()+" of "+get()+" Normal: "+super.toString(); + } + +} diff --git a/Java/ZZCursorReal.java b/Java/ZZCursorReal.java new file mode 100644 index 0000000..ad1036a --- /dev/null +++ b/Java/ZZCursorReal.java @@ -0,0 +1,367 @@ +/* +ZZCursorReal.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A real cursor in a structure. + * This class also implements the commonly used + * static methods for convenience. + */ + +public class ZZCursorReal extends ZZCursor { +String rcsid = "$Id: ZZCursorReal.java,v 1.31.2.1 2002/02/10 12:37:40 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + ZZCell ccell; + public ZZCursorReal(ZZCell start) { + // ccell = start.h("d.cursor-cargo", -1); + // XXX ?? Which one is right? + ccell = start; + } + public ZZCell get() { return get(ccell); } + public void set(ZZCell c) { set(ccell, c); } + public int getOffs() { return getOffs(ccell); } + public void setOffs(int i) { setOffs(ccell, i); } + + /** Get the cell the given cursor cell or cargo cell is pointing to. + */ + static public final ZZCell get(ZZCell start) { + // XXX Maybe should be less allowing... + return start.h("d.cursor-cargo", -1). + h("d.cursor-list", -1).s("d.cursor", -1); + } + + /** Set the given cursor cell to point to a cell. + */ + static public void setcursor(ZZCell cur, ZZCell c) { + removeFromCursorList(cur); + if (c != null) addToCursorList(cur, c); + trigger(cur); + } + + /** Set the given cursor cargo to point to a cell. + * If a cursor is cargoed already, use it. If no cursor is cargoed, + * create one. + */ + static public void setcargo(ZZCell cargo, ZZCell c) { + if(cargo.s("d.cursor-cargo", -1) == null) + cargo.N("d.cursor-cargo", -1); + setcursor(cargo.h("d.cursor-cargo", -1), c); + } + + /** Set the given cursor cell or cursor cargo cell to point to a cell. + * This routine has an interesting heuristic about creating + * a cell on d.cursor-cargo: if + * the cell is already connected negwards on d.cursor or + * d.cursor-list, + * no cursor cargo cell is created, otherwise it is. + *

    + * XXX should this be deprecated in favor of setcursor and setcargo? + */ + static public final void set(ZZCell start, ZZCell c) { + // A rather intricate check: if there's nothing on d.cursor-cargo, + // create it but only if we're not going negwards on d.cursor or + // d.cursor-list already. + + if(start.s("d.cursor-list", -1) == null && + start.s("d.cursor", -1) == null) { + setcargo(start, c); + } else + setcursor(start, c); + } + + static public void set(ZZCell c, ZZCursor curs) { + set(c, curs.get()); + setOffs(c, curs.getOffs()); + } + + /** Create a new cursor cell pointing to another cell. + * Usually you use set to create a new cell, but sometimes you don't want + * to attach a cargo cell on d.cursor-cargo; create just creates a new + * cell on d.cursor and returns it. + */ + static public final ZZCell create(ZZCell c) { + ZZCell cur = c.N(); + addToCursorList(cur, c); + return cur; + } + + /** Attach a cursor to another one on d.cursor-cargo. + * The first cell is removed from its current d.cursor-cargo rank and + * inserted poswards behind the second one. Thus, the first cursor must + * be a cursor cargo cell, not a real cursor cell (connected negwards + * along d.cursor). + */ + static public final void attach(ZZCell which, ZZCell where) { + if(which.s("d.cursor", -1) != null || + which.s("d.cursor-list", -1) != null) + throw new ZZError("which is a real cursor cell"); + where.insert("d.cursor-cargo", 1, which); + trigger(which); + } + + /** Get the color associated with this cursor in the structure. + */ + public java.awt.Color getColor() { return getColor(ccell); } + + /** Get the color associated with the given cursor in the structure. + */ + static public final java.awt.Color getColor(ZZCell start) { + ZZCell hc = start.h("d.cursor-cargo", -1); + ZZCell col = hc.s("d.1", 1); + if(col == null) + return null; + try { + return new java.awt.Color(Integer.parseInt(col.getText())); + } catch(NumberFormatException e) { + return null; + } + } + + /** Get the color associated with the given cursor, or white. + * Return Color.white if no color is associated in the structure; + * getColor would return null. + */ + static public final java.awt.Color getColorOrWhite(ZZCell start) { + java.awt.Color c = getColor(start); + if(c == null) return java.awt.Color.white; + return c; + } + + /** Set the color associated with the given cursor in the + * structure. + * XXX Move cursor color to another dimension... + */ + static public final void setColor(ZZCell start, java.awt.Color c) { + ZZCell hc = start.h("d.cursor-cargo", -1); + // if(hc.s("d.1", 1) != null) + // throw new Error("Can't set color of cursor: something's there."); + hc.getOrNewCell("d.1",1).setText(String.valueOf(c.getRGB())); + } + + /** Get the color of the first cursor associated with this cell. + * If there is no colored cursor accursing this cell, return null. + */ + static public final java.awt.Color getAccursedColor(ZZCell c) { + Enumeration e = ZZCursorReal.getPointers(c); + while(e.hasMoreElements()) { + java.awt.Color col = ZZCursorReal.getColor((ZZCell)e.nextElement()); + if(col != null) return col; + } + return null; + } + + /** Set the offset of the given cursor. + */ + static public void setOffs(ZZCell c, int i) { + String s = null; + if(i == NO_OFFSET) + s = ""; + else if(i < 0) { + throw new ZZError("Trying to set negative cursor offset!"); + } else + s = String.valueOf(i); + c.h("d.cursor-cargo", -1).setText(s); + trigger(c); + } + + /** Get the offset of the given cursor. + */ + static public int getOffs(ZZCell c) { + String s = c.h("d.cursor-cargo").getText(); + if(s==null || s.equals("")) return NO_OFFSET; + try { + int res = Integer.parseInt(s); + if(res < 0) { + ZZLogger.log( + "Serious: negative cursor offset. Resetting. "+c+" "+res); + setOffs(c, NO_OFFSET); + return NO_OFFSET; + } + return res; + } catch(NumberFormatException e) { + } + return NO_OFFSET; + } + + /** Delete extra cells associated only with the given cursor. + * After this, deleting the cell will remove all traces. + */ + static public void delete(ZZCell c) { + if(c.s("d.cursor-cargo", 1) != null) return; + c = c.s("d.cursor-cargo", -1); + if(c.s("d.cursor-cargo", -1) != null) return; + // Now, c is the cell on the cursor list with no other cargo, + // and is not the original cell. + removeFromCursorList(c); + c.delete(); + } + + static class PointerEnum implements Enumeration { + ZZCell c, cur; + { + p("PointerEnum created with " + c + ", cur = " + cur); + } + + public PointerEnum(ZZCell d) { + c = d; + cur = d.s("d.cursor", 1); + } + + public boolean hasMoreElements() { + boolean rv = cur != null; + p("PointeEnum: hasMoreElements:" + rv); + return rv; + } + + public Object nextElement() { + if (cur == null) throw new NoSuchElementException(); + Object rv = cur; + cur = cur.s("d.cursor-list", 1); + p("PointerEnum: rv = " + rv + ", cur = " + cur); + return rv; + } + } + + /** Find cursors that point to the given cell. + * This enumeration goes through the cells on the cursor list, + * note that each of those may have cursor cargo attached with + * them. There is not yet a function to go through the cursor + * cargoes. + */ + static public Enumeration getPointers(final ZZCell c) { + return new PointerEnum(c); + } + + /** Adjust the cursors on a cell after text insertion or deletion. + * This in- or decrements cursors whose offsets are past a given + * division point. Cursors without offsets remain unchanged. + * @param acc The cell on which the cursors to be changed are. + * @param div The index from which on we want offsets to be changed. + * @param inc The amount by which we want offsets to be changed. + * Negative for deletions. Note that offsets won't be set + * below div, that is after we've deleted seven characters, + * a cursor which was on the third character will be set + * where the first char was, not (7-3=)four posns before that. + */ + static public void adjustCursors(ZZCell acc, int div, int inc) { + Enumeration e = getPointers(acc); + while(e.hasMoreElements()) { + ZZCell curs = (ZZCell)e.nextElement(); + int offs = getOffs(curs); + if(offs != NO_OFFSET && offs >= div) { + if(offs + inc < div) + setOffs(curs, div); + else + setOffs(curs, offs + inc); + } + } + } + + /** Find the visual text offset for the cursor. + * This is purely a convenience routine: if the cursor has an + * offset, it returns that, but if not, it returns half of the + * length of text in the accursed cell. + */ + static public int getVisualTextOffset(ZZCell c) { + int ret = getOffs(c); + if(ret == NO_OFFSET) + ret = get(c).getText().length() / 2; + return ret; + } + + // Private stuff + + static private void removeFromCursorList(ZZCell cur) { + ZZCell acc = cur.s("d.cursor", -1); + if(acc != null) + cur.disconnect("d.cursor", -1); + + ZZCell nb = cur.s("d.cursor-list", 1); + if(acc != null && nb != null) + nb.connect("d.cursor", -1, acc); + + cur.excise("d.cursor-list"); + } + + static private void addToCursorList(ZZCell cur, ZZCell c) { + ZZCell nb = c.s("d.cursor", 1); + if(nb != null) + // insert instead of connect so that when we have headcells on + // looping ranks, d.cursor-list can loop. (Dunno if we need this, + // but kinda seemed right.) + nb.h("d.cursor-list", 1) + .insert("d.cursor-list", 1, cur); + else + c.connect("d.cursor", 1, cur); + } + + static private LoopDetector trigdetect = null; + static private boolean stoptrig = false; + + static private void trigger(ZZCell start) { + p("Cursor trigger triggered"); + boolean wasnull = false; + if(trigdetect == null) { + wasnull = true; + trigdetect = new LoopDetector(); + } + + synchronized(trigdetect) { + try { + ZZCell c = start.h("d.cursor-cargo", -1); + for(; c != null; c = c.s("d.cursor-cargo", 1)) { + if(c.s("d..cursor-trigger", -1) == null) continue; + p(""+c); + + if(trigdetect.isLooping(c)) { + ZZLogger.log("Detected trigger loop while trying "+ + "to set a cursor. Breaking triggering now."); + stoptrig = true; + break; + } + + ZZCell commcell = c.h("d..cursor-trigger", -1); + ZZCommand comm = ZZCommand.getCommand(commcell); + if(comm != null) { + p("Calling trigger command: "+commcell.getText()); + try { + comm.exec(c); + } catch(ZZError e) { + ZZLogger.exc(e, "Cursor trigger exception: "); + stoptrig = true; + } + if(stoptrig) break; + } + } + } finally { + if(wasnull) { + trigdetect = null; + stoptrig = false; + } + } + } + } +} diff --git a/Java/ZZCursorVirtual.java b/Java/ZZCursorVirtual.java new file mode 100644 index 0000000..283f256 --- /dev/null +++ b/Java/ZZCursorVirtual.java @@ -0,0 +1,61 @@ +/* +ZZCursorVirtual.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A virtual cursor. + * Used by clang to optimize away some puts and gets, e.g. to postpone + * setting the view cursor in the structure until the end of the routine. + * XXX Clang definition needs to be VERY specific about what timings + * are guaranteed in storing things to the structure. + */ +public class ZZCursorVirtual extends ZZCursor { +String rcsid = "$Id: ZZCursorVirtual.java,v 1.7 2000/11/25 00:36:33 tjl Exp $"; + ZZCell val; + int offs; + + public ZZCursorVirtual(ZZCell startVal) { + val = startVal; + offs = NO_OFFSET; + } + public ZZCursorVirtual(ZZCell startVal, int startOffset) { + val = startVal; + offs = startOffset; + } + public ZZCursorVirtual(ZZCursor curs) { + val = curs.get(); + offs = curs.getOffs(); + } + + static public ZZCursorVirtual createFromReal(ZZCell curs) { + return new ZZCursorVirtual(ZZCursorReal.get(curs), + ZZCursorReal.getOffs(curs)); + } + + public ZZCell get() { return val; } + public void set(ZZCell c) { val = c; } + public int getOffs() { return offs; } + public void setOffs(int i) { offs = i; } +} + + diff --git a/Java/ZZDefaultSpace.java b/Java/ZZDefaultSpace.java new file mode 100644 index 0000000..c0d4fc6 --- /dev/null +++ b/Java/ZZDefaultSpace.java @@ -0,0 +1,1087 @@ +/* +ZZDefaultSpace.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +/* + * `He looks as though someone hit him on the head,' said Chidder. + * `No-one did, did they?' + * Arthur shook his head. Teppic's face was locked in a gentle + * grin. Whatever his eyes were focused on wasn't occupying the usual + * set of dimensions. + * Terry Pratchett, Pyramids, p.78 + */ + +package org.gzigzag; +import java.awt.*; +import java.util.*; + +/** A "simple" class to create a default space starting at a cell. + * NOT FINISHED. + *

    + * This class is kind of a center for things to be changed later. + * It could be thought of as a bad design but the very point is that + * in order to find the change-sensitive places, you grep the source + * for ZZDefaultSpace and find out what places do what. + *

    + * It is not meant to remain here once things start settling down - probably. + * Or possibly something like it will, defining a schema somewhere for things, + * and other places just reference the schema - adaptive programming, anyone? + * Actually, after we bootstrap, it'll definitely be gone. + */ + +public class ZZDefaultSpace { +public static final String rcsid = "$Id: ZZDefaultSpace.java,v 1.143.2.2 2002/02/16 15:19:25 tuukkah Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + public static final String dimListDimen = "d.2"; + + public static final String sysList = "d.system"; + + // XXX See if abstracting this out would make sense... + static class ZP { + class StrCell { + String name; ZZCell val; + StrCell(String name, ZZCell val) { this.name = name; this.val = val; } + } + String name; + String type; + Vector pars = new Vector(); + ZP(String name, String type) { this.name = name; this.type = type; } + void ap(String name) { + pars.addElement(new String[] {name}); + } + void ap(String name, String val) { + pars.addElement(new String[] {name, val}); + } + void ap(String name, ZZCell val) { + pars.addElement(new StrCell(name, val)); + } + void ap(String name, String val, String val2) { + pars.addElement(new String[] {name, val, val2}); + } + void inh(ZZCell inhfrom) { + pars.addElement(inhfrom); + } + ZZCell ins(ZZCell c) { + ZZCell h = c.N("d.2", 1); + ZZCell ret = h; + h.setText(name); h = h.N("d.1", 1); + h.setText(type); h = h.N("d.1", 1); + for(Enumeration e = pars.elements(); + e.hasMoreElements(); ) { + Object el = e.nextElement(); + if(el instanceof String[]) { + String[] a = (String[])el; + h = h.N("d.2", 1); + h.setText(a[0]); + ZZCell cur = h; + for(int i=1; i + * This function should be used to access those cells + * so that the exact mechanism (dimensions etc.) may be later changed. + *

    + * The return value may be null in the case that there is a + * d.cursor-cargo attached to the cell + */ + static public ZZCell getPossDerefCell(ZZCell c) { + ZZCell cur = c; + // XXX LoopDetector + while(true) { + ZZCell m = ZZCursorReal.get(c); + if(m==null) return cur; + cur = m; + } + } + + // XXX NOTE: THIS GOES NEGWARDS - SPACE <-> SCROLL MAPPING + // MUST BE SAVED BETWEEN RESTARTS + static public ZZCell findScrollCell(ZZCell root, String id) { + ZZCell c = root; + c = c.findText("d.2", -1, "Scrolls"); + if(c==null) throw new ZZError("No scrolls!"); + c = c.findText("d.1", 1, id); + return c; + } + + // Currently: go along + static public ZZCell findInheritableParam(ZZCell start, String id) { + ZZCell n = start; + while(n!=null) { + if(n.getText().equals(id)) return n; + ZZCell h; h = n.h("d.3", -1); + if(h!=null && h!=n) { + h = findInheritableParam(h, id); + if(h!=null) return h; + } + n = n.s("d.2", 1); + } + return null; + } + + static public Font findInheritableParamFont(ZZCell start, String id, + Font def) { + ZZCell fo = findInheritableParam(start, id); + if(fo!=null) { + fo = fo.s("d.1",1); + String name = fo.getText(); + fo = fo.s("d.1",1); + int size = Integer.parseInt(fo.getText()); + return new Font(name,Font.PLAIN,size); + } + return def; + } + + static public float[] paramFloatA(ZZCell start, String id, float[] def, + int nmin) { + ZZCell p = findInheritableParam(start, id); + if(p==null) return def; + ZZCell[] r = p.readRank("d.1", 1, false); + if(r.length < nmin) return def; + float[] arr = new float[r.length]; + for(int i=0; i 0 ) + str = str.substring(0, str.length()-1); + c.setText(str); + } else + c.setText(c.getText() + str); + } + + static public ZZScene getScene(ZZCell view, Component forc) { + p("getScene: startflob"); + Dimension size = forc.getSize(); + FlobSet fs = new FlobSet(size, forc.getForeground(), + forc.getBackground(), forc); + ZZCell c = findInheritableParam(view, "View"); + ZZCell rastname = ZZCursorReal.get(c); + + ZOb frz = readZOb(rastname); + FlobView fr = null; + if(frz != null && frz instanceof FlobView) { + fr = (FlobView)frz ; + } else { + System.out.println("getScene: invalid type: "+frz); + fr = new NullView(); + } + // XXX Signal error + + c = findInheritableParam(view, "CellView"); + + FlobFactory rff = null; + if(c != null) { + ZZCell cfact = ZZCursorReal.get(c); + + ZOb ffzob = readZOb(cfact); + rff = (FlobFactory) ffzob; + } + + p("getScene: raster"); + fr.raster(fs, rff, view, getDimList(view), ZZCursorReal.get(view)); + p("getScene: rastered"); + + if(rff != null) { + Flob rn = rff.placeFlob(fs, rastname, rastname, (float)1.5, size.width, 0, 1, 1, 0); + rn.flobPath="rastname"; + } + return fs; + } + + // static void newScroll(ZZCell root, String id, String addr) { + // } + + static public String getLang(ZZCell window) { + ZZCell c = findInheritableParam(window, "Language"); + if(c == null) return "en"; + c = c.s("d.1"); + if(c == null) return "en"; + if(c.getText().length() < 2) return "en"; + return c.getText(); + } +} diff --git a/Java/ZZDimSpace.java b/Java/ZZDimSpace.java new file mode 100644 index 0000000..e221713 --- /dev/null +++ b/Java/ZZDimSpace.java @@ -0,0 +1,442 @@ +/* +ZZDimSpace.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka (ID-stuff and d.cellcreation by Tuukka Hastrup) + */ +package org.gzigzag; +import java.util.*; + +/** A dimension-centric implementation of a space. + * The internals of this implementation are done by dimension objects + * which know how cells are connected in their dimension. + * @see ZZDimension + */ + +public class ZZDimSpace extends ZZSpace { +public static final String rcsid = "$Id: ZZDimSpace.java,v 1.49 2001/03/07 12:51:24 ajk Exp $"; + +// XXX These should be made garbage collectable ASAP! + + /** ZZDimension given string. */ + Hashtable dims = new Hashtable(); + + /** DimCell given id. */ + Hashtable cells = new Hashtable(); + + /** Space parts by names. */ + Hashtable spaceParts = new Hashtable(); + + /** Contents by id. */ + Hashtable contents = new Hashtable(); + + /** Cell by span. + * If this is null, overlapping spans cannot be searched. + */ + SpanSet spanset = null; + + public ZZDimSpace() { this(false); } + public ZZDimSpace(boolean readonly) { + super(readonly); + } + + /** Obtain the space part corresponding to the given ID. + */ + public ZZSpacePart getSpacePartByID(String id) { + return (ZZSpacePart)spaceParts.get(id); + } + + /** Obtain the ZZDimension corresponding to the given string. + */ + final public ZZDimension d(String s) { + ZZDimension r = (ZZDimension)dims.get(s); + if(r==null) { + r = createDimension(s); + if(r == null) + throw new ZZError("Illegal dimension: '"+s+"'"); + dims.put(s,r); + if (!readonly) updateMasterDimList(s); + } + return r; + } + + /** The cell given by the identifier, if already created. + * Note that this routine only returns existing cells, + * i.e. objects that have already been created. + * Dormant cells or virtual cells need to be obtained through + * getCellByID. + */ + DimCell c(String id) { return (DimCell)cells.get(id); } + + /** Obtain the cell given by the identifier. + */ + public ZZCell getCellByID(String s) { + int at = s.indexOf('@'); + if (at != -1 && getIDOrNull() != null && s.substring(at+1).equals(getID())) { + s = s.substring(0, at); + at = -1; + } + int ind = s.indexOf(':'); + if (at == -1 && ind == -1) { + try { + if (nextID != null) { + long cid = Long.parseLong(s); + long nid = Long.parseLong(nextID); + if (cid >= nid) setNextID("" + (cid+1)); + } + } catch(NumberFormatException e) { + return null; + } + } + if(ind != -1) { + ZZSpacePart part = getSpacePartByID(s.substring(0, ind)); + if(part == null) + throw new ZZError("No such part for cell "+s); + return getCellByID(part, s.substring(ind+1)); + } + return getCellByID(null, s); + } + + /** Obtain a cell, possibly in a space part. + */ + public DimCell getCellByID(ZZSpacePart p, String s0) { + String s = (p != null ? p.id + ":" + s0 : s0); + DimCell ret = null; + if (p != null) ret = p.getCellByID(s0); + if (ret == null) ret = (DimCell) cells.get(s); + if(ret==null) { + DimCell d = new DimCell(s, p, + (p != null ? p.parseIDPart(s0) : null)); + cells.put(d.id, d); + ret = d; + } + return ret; + } + + public DimCell getCellByID(ZZSpacePart p, String s0, Object o) { + String s = p.id + ":" + s0; + DimCell ret = null; + if (p != null) ret = p.getCellByID(s0); + if (ret == null) ret = (DimCell) cells.get(s); + if(ret==null) { + DimCell d = new DimCell(s, p, o); + cells.put(d.id, d); + ret = d; + } + return ret; + } + + public ZZCell[] overlaps(Span sp) { + if(spanset == null) return null; + Object[] o = spanset.overlaps(sp); + ZZCell[] res = new ZZCell[o.length]; + for(int i=0; i + * The reason for this is that it needs to be allowable for + * two cell objects with the same ID to be created without + * too much confusion. + *

    + * This is because we're aiming for Java 1.1 which does not + * have weak references. + */ + public class DimCell extends ZZCellHandle { + + protected DimCell(String id) { + super(id, null, null); + } + protected DimCell(ZZSpacePart part, Object parsedID) { + this(part.generateID(parsedID), part, parsedID); + } + + protected DimCell(String id, ZZSpacePart p, Object o) { + super(id, p, o); + } + + public String[] getRankNames() { + throw new ZZError("getRankNames Not implemented"); + } + + public final ZZSpace getSpace() { return ZZDimSpace.this; } + + public void connect(String dim, ZZCell to) { + this.disconnect(dim, 1); + to.disconnect(dim, -1); + d(dim).connect(this, ((DimCell)to)); + } + public void disconnect(String dim, int dir) { + d(dim).disconnect(this, dir); + } + public void insert(String dim, int dir, ZZCell to) { + d(dim).insert(this, dir, ((DimCell)to)); + } + public void hop(String dim, int steps) { + d(dim).hop(this, steps); + } + + public ZZCell s(String dim, int dir, ZZObs o) { + return d(dim).s(this, dir, o); + } + + public ZZCell N(String dim, int dir, ZZObs o, long flags) + { + synchronized(ZZDimSpace.this) { + DimCell n = getNewCell(id); + insert(dim, dir, n); + if(o != null) + d(dim).s(this, dir, o); + return n; + } + } + + public ZZCell N() { + synchronized(ZZDimSpace.this) { + return getNewCell(id); + } + } + + public void setText(String text) { + synchronized(ZZDimSpace.this) { + ZZCell rootClone = getRootclone(); + if(rootClone != this) { + rootClone.setText(text); + return; + } + if(part != null) { + part.setContent(this, text); + } else { + p("TEXT"); + ZZDimSpace.this.setText(id, text); + textTrig.chg(id); + } + } + } + public void setSpan(Span text) { + synchronized(ZZDimSpace.this) { + ZZCell rootClone = getRootclone(); + if(rootClone != this) { + rootClone.setSpan(text); + return; + } + if(part != null) { + part.setContent(this, text); + } else { + ZZDimSpace.this.setText(id, text); + textTrig.chg(id); + } + } + } + + // XXX part.getText should NOT BE HERE!!!! + public String getText(ZZObs o) { + synchronized(ZZDimSpace.this) { + String s; + // XXX Interaction with slices?? + // XXX Interaction with ZZObs + ZZCell rootClone = getRootclone(); + if(rootClone != this) + return rootClone.getText(o); + if(o != null) textTrig.addObs(id, o); + if(part != null) + s = part.getText(this); + else + s = ZZDimSpace.this.getText(id); + if( s == null ) + return ""; + return s; + } + } + public Span getSpan(ZZObs o) { + synchronized(ZZDimSpace.this) { + ZZCell rootClone = getRootclone(); + // XXX As in getText!!! + if(rootClone != this) + return rootClone.getSpan(o); + if(o != null) textTrig.addObs(id, o); + if(part != null) + return part.getSpan(this); + return ZZDimSpace.this.getSpan(id); + } + } + + public boolean equals(ZZCell c) { + DimCell o = (DimCell)c; + return (this == o) || + (ZZDimSpace.this == o.getSpace() && + id.equals(o.id)); + } + + public void delete() { + synchronized(ZZDimSpace.this) { + ZZDimSpace.this.deleteCell(this); + } + } + + public ZZCell h(String dim, int dir, + boolean ensuremove, ZZObs o) { + ZZCell res = d(dim).h(this, dir, o); + if(ensuremove && (res == this)) return null; + return res; + } + + } + + void deleteCell(ZZCell c) { + for(Enumeration e = dims.keys(); e.hasMoreElements(); ) { + ((ZZDimension)(dims.get(e.nextElement()))).excise((DimCell)c); + } + } + + String nextID="2"; // first cell is home cell, ID 1 + protected void setNextID(String s) { + nextID = s; + } + + /** Get the cell ID relative to a given ID, in creation order. + * @param id Given ID + * @param steps How many steps to take (negative means earlier) + */ + public String getRelativeCellID(String id, int steps) { + try { + long i = Long.parseLong(id); + if(i<0 || i+steps<1) + return null; + return ""+(i+steps); + } catch(NumberFormatException e) { + return null; + } + } + protected String getFreeCellID() { + String curID = nextID; + setNextID(getRelativeCellID(nextID, 1)); + return curID; + } + + // XXX What's this? (compared to the next) + protected DimCell getNewCell(String id) { + return getNewCell(); + } + protected DimCell getNewCell() { + return (DimCell)getCellByID(nextID); + } + public ZZCell newCell() { + return getNewCell(); + } + + /** A simple dimension listing the cells in creation order. + * It uses getRelativeCellID() to find the cells, and will check + * nextID to know whether the cell doesn't exist yet. + * XXX The positive steps taken must be 1 or skipping nextID + * is possible! + */ + class IDDimension extends ZZRODimension { + /** get a cell ID along the dimension. + * XXX Obs doesn't work correctly. + */ + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + String id = getRelativeCellID(c.id, steps); + if(id == null || id.equals(nextID)) + return null; + return (DimCell)getCellByID(id); + } + } + + + + // XXX posConnections()? + public ZZCell[] findLongRankHeads(String dim) { return null; } + + public void rmAllObs(ZZObs o) { } + + public String getHomeCellID() { + return "1"; + } + public ZZCell getHomeCell() { + return getCellByID(getHomeCellID()); + } + + /** Create a new dimension with the name s. + * In order to make things fast, this is the method + * to override instead of the d() method (which is final + * exactly because of that). + *

    + * The default version simply returns a new ZZLocalDimension, + * except for d.cellcreation + *

    + * Note that this routine should NOT touch the dimension hash + * but simply return the new dimension. + */ + protected ZZDimension createDimension(String s) { + if(s.indexOf(':') != -1) return createPartDimension(s); + if(!validDim(s)) return null; + ZZDimension l; + if(s.equals("d.cellcreation")) { + l = new IDDimension(); + } else { + l = new ZZLocalDimension(); + } + l.setSpace(this); + return l; + + } + + protected ZZDimension createPartDimension(String s) { + int ind = s.indexOf(':'); + ZZSpacePart part = getSpacePartByID(s.substring(0, ind)); + ZZDimension d = part.getDim(s.substring(ind+1)); + d.setSpace(this); + return d; + } + + +} + diff --git a/Java/ZZDimension.java b/Java/ZZDimension.java new file mode 100644 index 0000000..f4bb936 --- /dev/null +++ b/Java/ZZDimension.java @@ -0,0 +1,178 @@ +/* +ZZDimension.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** Dimension-centric implementation. + * A ZZDimension represents a single dimension of a space. + * It is called with the cell objects that simply contai. + *

    + * Some of the routines are given here so that they may be optimized. + * The absolute core routines that every subclass must implement + * are the abstract routines s, connect and disconnect. + */ + +public abstract class ZZDimension { +public static final String rcsid = "$Id: ZZDimension.java,v 1.25 2001/01/24 08:32:16 veparkki Exp $"; + + /** The space this dimension is affiliated with. */ + protected ZZDimSpace space; + public void setSpace(ZZDimSpace s) { space = s; } + + /** The observer trigger for this dimension. + */ + protected ZZObsTrigger triggers = new ZZObsTrigger(); + + // These three routines need to be implemented + + /** Get another cell steps steps on the dimension from c. + * @param c The cell + * @param steps Number of steps, can be negative. + */ + public abstract ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o); + /** Connect the two cells in this dimension, in order. + */ + public abstract void connect(ZZCellHandle c, ZZCellHandle d); + /** Disconnect the cell in the given direction. + */ + public abstract void disconnect(ZZCellHandle c, int dir); + + // Really throw out the old functions and + // make them so that no-one can override them. + +/* + final public String s(String c, int steps, ZZObs o) + { throw new ZZError("Old dim API"); } + final public void connect(String c, String d) + { throw new ZZError("Old dim API"); } + final public void disconnect(String c, int dir) + { throw new ZZError("Old dim API"); } + */ + + + /** The rest of the operations from here can be overridden + * for optimizations, but do it is not required: the above operations + * are all that is really needed. + */ + + /** Get headcell. + */ + + // XXX loops + public ZZCellHandle h(ZZCellHandle c, int dir, ZZObs o) { + ZZCellHandle orig = c; + ZZCellHandle prev = c; + while((c=s(c, dir, o))!=null) { + prev = c; + // Return lexically maximum id. + if(c.equals(orig)) { + // throw new ZZInfiniteLoop("CIRCULAR HEAD"); + ZZCellHandle lid = c; + while((c=s(c ,dir, o))!=null + && !c.equals(orig)) { + if(c.id.compareTo(lid.id) > 0) lid = c; + } + return lid; + } + } + return prev; + } + + public ZZCellHandle h(ZZCellHandle c, int dir) { + return h(c, dir, null); + } + + final void connect(ZZCellHandle c, int dir, ZZCellHandle d) { + if(dir<0) + connect(d,c); + else + connect(c,d); + } + + public void insert(ZZCellHandle c, int dir, ZZCellHandle d) { + ZZCellHandle p = s(d, 1); + ZZCellHandle m = s(d, -1); + //System.out.println("c = " + c); + //System.out.println("d = " + d); + //System.out.println("p = " + p); + //System.out.println("m = " + m); + + if(p!=null) + disconnect(p, -1); + if(m!=null) + disconnect(m, 1); + if(p!=null && m!=null) + connect(m, p); + ZZCellHandle o = s(c, dir); + if(o!=null) + disconnect(c, dir); + + connect(c,dir,d); + if(o!=null) + connect(d,dir,o); + } + + /** Remove the given cell from this dimension. + */ + public void excise(ZZCellHandle c) { + ZZCellHandle p = s(c, 1); + ZZCellHandle m = s(c, -1); + disconnect(c, 1); + disconnect(c, -1); + if(p!=null && m!=null) + connect(m, p); + } + + public void hop(ZZCellHandle c, int steps) { + if(steps == 0) return; + ZZCellHandle n = s(c, steps); + if(n == null ) return; + insert(n, (steps > 0 ? 1 : -1), c); + } + + /** Find the text in a cell. + * This routine is here so that it may be optimized if desired. + * If it is, then the main space object must remember to update + * this dimension if it keeps a cache in a hash etc. + */ + public ZZCellHandle findText(ZZCellHandle c, int dir, String txt) { + ZZCellHandle cur = s(c, 1); + while(cur != null && cur != c && + !cur.getText().equals(txt)) + cur = s(cur, 1); + if(cur==c) return null; + return cur; + } + + public ZZCellHandle s(ZZCellHandle c, int steps) { + return s(c, steps, null); + } + + // Same goes for these, obviously + // ZZCell intersect(ZZCell c, int dir, ZZDimension d2, ZZCell c2, int dir2); + // ZZCell[] intersectAll(ZZCell c, int dir, ZZDimension d2, ZZCell c2, int dir2); + + + + +} diff --git a/Java/ZZDrawing.java b/Java/ZZDrawing.java new file mode 100644 index 0000000..d14f351 --- /dev/null +++ b/Java/ZZDrawing.java @@ -0,0 +1,106 @@ +/* +ZZDrawing.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** An abstraction of improved drawing primitives. + * We are aiming for Java 1.1, but for instance Java2D provides + * many features we'd like to use, if present. + * Normally, simply testing

    g instanceof Graphics2D
    + * would be sufficient but we want to also be able to compile + * with only the 1.1 libraries available, so we cannot do that. + * Also, we want to be able to hook up to e.g. OpenGL without + * having to create a full Java2D implementation there. + *

    + * This class is used to abstract out any graphics operations that + * are not in java.awt.Graphics. The default of this class is that + * each operation is a no-op (unless otherwise specified). + * All code should function reasonably under such an assumption. + * Subclasses of this object are allowed to implement operations + * in any way they like. + *

    + * TODO: Should make it possible to get drawing parameters + * from either system + * properties (possibly preferable) or the ZZ structure. + */ + +public class ZZDrawing { +public static final String rcsid = "$Id: ZZDrawing.java,v 1.6 2001/03/26 12:41:00 tjl Exp $"; + + /** Get a human-readable string identifying the ZZDrawing + * instance and the settings. + */ + public String getType() { + return "Default 1.1 API -compliant version: no antialiasing or rotation"; + } + + /** The default instance of ZZDrawing for others to use. + */ + static public final ZZDrawing instance = createInstance(); + private boolean qEnabled = true; + + /** Create an instance. + */ + static public ZZDrawing createInstance() { + ZZDrawing ret = null; + Class g2d = null, zzdj2d = null; + try { + g2d = Class.forName("java.awt.Graphics2D"); + zzdj2d = Class.forName("org.gzigzag.ZZDrawingJ2D"); + ret = (ZZDrawing)zzdj2d.newInstance(); + } catch(Exception e) { + ZZLogger.exc(e); + if(g2d != null) { + ZZLogger.log("Graphics2D found but support not compiled in."); + } + } + if(ret == null) ret = new ZZDrawing(); + return ret; + } + + /** Set rendering so that the graphics context will draw + * over translucently, with the given alpha. + */ + public void setAlpha(Graphics g, float alpha) { + } + + /** Set good rendering quality. + * XXX Should take a parameter. + */ + public void setQuality(Graphics g) { + } + + /** Return true if it makes any difference. */ + public boolean enableQuality(boolean t) { + qEnabled = t; + return false; + } + public boolean qualityEnabled() { return qEnabled; } + + /** Set the defaults. To be called on all + * Graphics objects used. + */ + public void setDefaults(Graphics g0) { + } +} + diff --git a/Java/ZZEvObs.java b/Java/ZZEvObs.java new file mode 100644 index 0000000..b572946 --- /dev/null +++ b/Java/ZZEvObs.java @@ -0,0 +1,36 @@ +/* +ZZEvObs.java + * + * Copyright (c) 1999, Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ + +package org.gzigzag; +/** A simple class that observes a cell. + * Note that this class is to be used only for one cell: the two calls + * chg(1) chg(2) can be replaced with chg(2). There will in the future be + * a new class, ZZMultiCellObs that gets a ZZCell[] as its parameter. + */ + +public interface ZZEvObs { +String rcsid = "$Id: ZZEvObs.java,v 1.5 2000/09/19 10:31:58 ajk Exp $"; + /** Called when something is changed. + */ + + void chg(); +} + + diff --git a/Java/ZZExec.java b/Java/ZZExec.java new file mode 100644 index 0000000..acc4052 --- /dev/null +++ b/Java/ZZExec.java @@ -0,0 +1,58 @@ +/* +ZZExec.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** A generic script engine interface. + * ZZExec specifies a way of interfacing various script engines to the ZZ space. + * At the moment, only UI callback functions are allowed - later, it will be + * expanded to a more complete class. + */ + +public interface ZZExec { +String rcsid = "$Id: ZZExec.java,v 1.12 2000/09/19 10:31:58 ajk Exp $"; + /** Execute some code as a callback from the user interface. + * This is a special execution context which is triggered through user + * action on an user interface. Note that some of the params + * are redundant and only provided for ease. All the other parameters + * can be deduced from code, view, ctrlview and clicked. + * @param code Cell to start execution from + * @param view View where command executed + * @param cview Control view of view where command executed + * @param key The key the user pressed, as string, if any + * @param pt The point the user clicked on, if any + * @param xi The extra object - to get what was clicked, if any + */ + void execCallback(ZZCell code, + ZZCell target, + ZZView view, + ZZView cview, + String key, + Point pt, + ZZScene xi + ); + // /** Execute some code with parameters. + // * XXX Needs rethinking of the arguments. + // */ + // public void exec(ZZCell code, ZZCell[] params); +} diff --git a/Java/ZZIter.java b/Java/ZZIter.java new file mode 100644 index 0000000..2bb52ad --- /dev/null +++ b/Java/ZZIter.java @@ -0,0 +1,162 @@ +/* +ZZIter.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.datatransfer.*; +import java.util.*; + +/** Help for iterating along ranks in various ways. + */ + +public class ZZIter { +public static final String rcsid = "$Id: ZZIter.java,v 1.3 2000/11/01 00:39:06 tjl Exp $"; + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + /** An callback interface for iterating along a rank with + * the cell number. + */ + public interface NIter { + /** Do whatever you like with this cell, which is the nth from + * wherever we began. + * @return True, if the iteration is to continue (in this direction). + */ + boolean go(ZZCell c, int nth); + } + + /** Go along a rank, starting from a cell, interleaving alternate + * directions. + * @param c The cell to start from. + * @param included Whether the first cell is also included. + * @param d The dimension to go along. + * @param fdir The direction to take the first step in. + * @param iter The callback object. + */ + public static void alternate(ZZCell c, boolean included, + String d, int fdir, NIter iter) { + if(c == null) return; + int i = 0; + if(included) + if(!iter.go(c, 0)) return; + boolean in = true; + boolean op = true; + ZZCell inc = c; + ZZCell opc = c; + while(in || op) { + i++; + if(in) { + inc = inc.s(d, fdir); + if(inc == null) + in = false; + else + if(!iter.go(inc, fdir * i)) + in = false; + } + if(op) { + opc = opc.s(d, -fdir); + if(opc == null) + op = false; + else + if(!iter.go(opc, -fdir * i)) + op = false; + } + } + } + + /** A cell enumeration, with index. + */ + public interface NEnum { + /** Get the next cell. + */ + ZZCell nextCell(); + /** Get the index of the last returned cell from nextCell. + */ + int nth(); + /** Whether there are more cells. + */ + boolean more(); + /** Stop advancing in the current direction. + */ + void stop(); + } + + /** Return an enumeration that alternates between the directions. + * @param c The cell to start from. + * @param included Whether the first cell is also included. + * @param d The dimension to go along. + * @param fdir The direction to take the first step in. + */ + public static NEnum alternate(final ZZCell c, final boolean included, final String d, final int fdir) { + return new NEnum() { + /** Next cell in p or n direction. + */ + ZZCell nextn = c.s(d, -fdir), nextp = c.s(d, fdir); + + int ind = 0; + + boolean started; + + public ZZCell nextCell() { + if(nextn == null && nextp == null) return null; + if(!started) { + started = true; + if(included) return c; + } + // Trick: always change ind, only after see if we have something + // to return. If not, recurse and get the next one from the other side. + if(ind <= 0) { + ind = -ind; + ind ++; + if(nextp == null) + return nextCell(); + ZZCell ret = nextp; + nextp = nextp.s(d, fdir); + return ret; + } + if(ind > 0) { + ind = -ind; + if(nextn == null) + return nextCell(); + ZZCell ret = nextn; + nextn = nextn.s(d, -fdir); + return ret; + } + return null; + } + public int nth() { + return fdir * ind; + } + public void stop() { + if(ind >= 0) nextp = null; + else nextn = null; + } + public boolean more() { + return nextn != null || nextp != null; + } + }; + } +} + + + diff --git a/Java/ZZKeyBindings.java b/Java/ZZKeyBindings.java new file mode 100644 index 0000000..82ff2b6 --- /dev/null +++ b/Java/ZZKeyBindings.java @@ -0,0 +1,39 @@ +/* +ZZKeyBindings.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.event.*; +import java.awt.*; + +/** A generic keybindings driver interface. + * The point of this interface is to allow experimentation + * with different ways of specifying keybindings in the ZigZag structure. + */ + +public interface ZZKeyBindings { +String rcsid = "$Id: ZZKeyBindings.java,v 1.13 2000/09/19 10:31:58 ajk Exp $"; + /** Perform a particular key or mouse + * event associated with a particular view. + */ + void perform(InputEvent k, ZZView v, ZZView ctrlv, ZZScene xi); +} + diff --git a/Java/ZZKeyBindings0.java b/Java/ZZKeyBindings0.java new file mode 100644 index 0000000..8a4e317 --- /dev/null +++ b/Java/ZZKeyBindings0.java @@ -0,0 +1,45 @@ +/* +ZZKeyBindings0.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.event.*; + +/** A very simple keybindings class which is hardcoded for the cursor keys. + * Does nothing else. OBSOLETE. + */ + /* +public class ZZKeyBindings0 implements ZZKeyBindings { +public static final String rcsid = "$Id: ZZKeyBindings0.java,v 1.7 2000/09/19 10:31:58 ajk Exp $"; + ZZCell current; + public void perform(KeyEvent k, ZZView v) { + // XXX Hardcoded - should update automatically from the structure.. + switch(k.getKeyCode()) { + case k.VK_UP: v.move(0,-1); break; + case k.VK_DOWN: v.move(0,1); break; + case k.VK_LEFT: v.move(-1,0); break; + case k.VK_RIGHT: v.move(1,0); break; + } + } +} + +*/ +class LIJFSELFJLISEFJLSEFSF { } diff --git a/Java/ZZKeyBindings1.java b/Java/ZZKeyBindings1.java new file mode 100644 index 0000000..7e9d910 --- /dev/null +++ b/Java/ZZKeyBindings1.java @@ -0,0 +1,319 @@ +/* +ZZKeyBindings1.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; + +/** The first meaningful keybindings class. + * A stateless class which looks along d.2 for a string matching + * the result of the getKeyText method of the java.awt.event.KeyEvent class. + */ + +public class ZZKeyBindings1 implements ZZKeyBindings { +public static final String rcsid = "$Id: ZZKeyBindings1.java,v 1.61.2.2 2001/08/16 14:51:24 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + static final void pa(String s) { ZZLogger.log(s); } + + /** Create ZZKeyBindings1. + @deprecated Use the noarg constructor instead. */ + ZZKeyBindings1(ZZExec x) { this(); } + ZZKeyBindings1() {} + + Point origpt; + boolean dragging = false; + + public void perform(InputEvent ie, ZZView v, ZZView ctrlv, ZZScene xi) { + ZZCell vcell = v.getViewcell(); + + String t = null; + p(" "+ie); + if(ie instanceof KeyEvent) { + /* + * This is quite complicated - more complicated than it + * should be but Java seems to screw up key events quite + * nicely for us... + * We want to have Shift-Alt-X, for example, which on some + * Javas needs quite a bit of attention. + */ + KeyEvent k = (KeyEvent) ie; + char c= k.getKeyChar(); + int kc = k.getKeyCode(); + String kt = KeyEvent.getKeyText(kc); + String kbychar = new String(new char[] {c}); + p("Have: "+c+" "+kc+" '"+kt+"' '"+kbychar+"'"); + if((c == k.CHAR_UNDEFINED + // k.CHAR_UNDEFINED changed between JDK1.1 and 1.2 + || c == 0x0 || c == 0xFFFF // needed for cross-compiling + || kc == k.VK_DELETE + || kc == k.VK_BACK_SPACE) + && kc != 0) + t = kt; + else + t = kbychar; + p("Chose: "+t); + if(t.equals("\n")) t = "Enter"; + if(t.equals("\t")) t = "Tab"; + if(t.equals("\033")) t = "Esc"; + if(t.equals("") || + Character.isISOControl(t.charAt(0)) || + k.isAltDown() || k.isControlDown() || + kt.equals("Left") || // These need shift. + kt.equals("Right") || + kt.equals("Up") || + kt.equals("Down") + ) { + p("Maybe rechoosing"); + if(kc != 0) + t = kt; + if(k.isShiftDown()) t = "Shift-"+t; + } + if(k.isAltDown()) t = "Alt-"+t; + if(k.isControlDown()) t = "Ctrl-"+t; + + p("KEYTEXT: '" + t + "', was by kt: '"+kt+"' and by char: '" + +kbychar+"'"); + if(t==null) return; + perf(t, null, v, ctrlv, t, null, xi); + } else if(ie instanceof MouseEvent) { + MouseEvent m = (MouseEvent)ie; + String modstr = ""; + + if(m.isAltDown()) modstr = "Alt-"+modstr; + if(m.isControlDown()) modstr = "Ctrl-"+modstr; + if(m.isShiftDown()) modstr = "Shift-"+modstr; + + Point pt = new Point(m.getX(), m.getY()); + String mec = null; + ZZCell targ = null; + if(m.getID() == m.MOUSE_CLICKED) { + mec = "Clicked"; + dragging = false; + // If it was a cell, give it as the target. + // XXX Need we really do this here? + Object ob = xi.getObjectAt(m.getX(), m.getY()); + if(ob instanceof ZZCell) targ = (ZZCell) ob; + + // Call applitude manager, to change app if necessary + // (Actually, just realized: because we do this here, before + // we call perf(), the applitude bindings of the new + // applitude are used, which is exactly what we want!) + ApplitudeMgr.clicked(vcell, xi, pt); + } else if(m.getID() == m.MOUSE_PRESSED) { + mec = "Pressed"; + origpt = pt; + dragging = false; + } else if(m.getID() == m.MOUSE_DRAGGED) { + mec = "Dragged"; + if(!dragging) { + perf(modstr+"MouseStartDrag", null, v, ctrlv, null, origpt, xi); + dragging = true; + } + } else if(m.getID() == m.MOUSE_RELEASED) { + mec = "Released"; + dragging = false; + // XXX EndDrag? + } else + return; + int but = 0; + int mod = m.getModifiers(); + if((mod & m.BUTTON1_MASK) != 0) but = 1; + else if((mod & m.BUTTON2_MASK) != 0) but = 2; + else if((mod & m.BUTTON3_MASK) != 0) but = 3; + + t = modstr+"Mouse"+mec+but; + + p("MOUSE: '"+t+"': event was "+m); + + perf(t, targ, v, ctrlv, null, pt, xi); + + } + } + + /** Get the key bindings mode cursor associated with this window. + * Does currently not create a new one if there is none. + * Instead, returns null. + */ + public static ZZCell getModeCursor(ZZCell window) { + return window.h("d.bind", 1, true); + } + + /** Get the key bindings mode cell associated with this window. + * Set to default mode if no mode is there. + */ + public static ZZCell getMode(ZZCell window) { + ZZCell c0 = getModeCursor(window); + if(c0 == null) { + p("NO BIND YET: SET CURS"); + c0 = window.N("d.bind", 1); + ZZCell cur0 = ZZDefaultSpace.findOnSystemlist( + window.getSpace(), "Bindings", false).s("d.1", 1); + ZZCursorReal.set(c0, cur0); + ZZCursorReal.setColor(c0, new Color(0xaf5a00)); + } + return ZZCursorReal.get(c0); + } + + void perf(String id, ZZCell target, + ZZView v, ZZView ctrl, String key, Point pt, ZZScene xi) { + p("PERF: '"+id+"'"); + ZZCell vcell = v.getViewcell(); + ZZCell accursed = ZZCursorReal.get(vcell); + ZZCell cvcell = ctrl.getViewcell(); + ZZCell cur = getMode(vcell); + p("BIND CURS: "+cur+" "+(cur!=null?cur.getID():null)); + + /** Use applitude bindings? + * As not all views show applitude data, views which do have to + * have an "appbindings" structparam to declare the bindings of the + * applitude currently prefered by this window shall be used. + */ + boolean useAppBinds = false; + + /** Is the binding found an applitude binding? + * This affects how the bindings mode is changed. + */ + boolean isAppBind = false; + + ZZCell raster = + ZZDefaultSpace.findInheritableParam(vcell, "View"); + if(raster != null) raster = ZZCursorReal.get(raster); + if(raster != null) raster = raster.h("d.clone", -1); + if(raster != null) raster = raster.s("d.1", 2); + if(ZZDefaultSpace.findInheritableParam(raster, "appbindings") != null) + useAppBinds = true; + if(raster != null) raster = + ZZDefaultSpace.findInheritableParam(raster, "databindings"); + if(raster != null) raster = raster.intersect("d.1",1,cur,"d.clone",1); + + ZZCell craster = + ZZDefaultSpace.findInheritableParam(cvcell, "View"); + if(craster != null) craster = ZZCursorReal.get(craster); + if(craster != null) craster = craster.h("d.clone", -1); + if(craster != null) craster = craster.s("d.1", 2); + if(craster != null) craster = + ZZDefaultSpace.findInheritableParam(craster, "ctrlbindings"); + if(craster != null) craster = craster.intersect( + "d.1", 1, cur, "d.clone", 1); + + ZZCell binding = null; + if(raster != null) { + binding = ZZDefaultSpace.findInheritableParam(raster, id); + p("Tried by view"); + } + if(binding == null && useAppBinds) { + ZZCell app = ApplitudeMgr.getAppBindsForWin(vcell); + binding = ZZDefaultSpace.findInheritableParam(app, id); + p("Tried by applitude"); + if(binding == null && key != null && key.length() > 0) { + binding = ZZDefaultSpace.findInheritableParam(app, "INSERT"); + p("Tried by applitude INSERT"); + } + if(binding == null) { + binding = ZZDefaultSpace.findInheritableParam(app, "DEFAULT"); + p("Tried by applitude DEFAULT"); + } + if(binding != null) + isAppBind = true; + } + if(binding == null && craster != null) { + binding = ZZDefaultSpace.findInheritableParam(craster, id); + p("Tried by ctrl view"); + } + if(binding == null) { + binding = ZZDefaultSpace.findInheritableParam(cur, id); + p("Tried by cur"); + } + if(binding == null && key != null && key.length() == 1) { + binding = ZZDefaultSpace.findInheritableParam(cur, "INSERT"); + } + if(binding == null) { + binding = ZZDefaultSpace.findInheritableParam(cur, "DEFAULT"); + p("Tried by DEFAULT"); + } + if(binding == null && + ZZDefaultSpace.findInheritableParam(cur, "EDITBINDS") != null) { + ZZCell cellview = accursed.h("d.cellview", true), ecur = null; + p("cellview: "+cellview); + if(cellview != null) + cellview = cellview.s("d.1", 2); + if(cellview != null) + cellview = ZZDefaultSpace.findInheritableParam(cellview, "EditBindings"); + if(cellview != null) + ecur = cellview.s("d.1", 1); + p("editbinds cur: "+ecur); + if(ecur == null) + ecur = ZZDefaultSpace.findOnSystemlist(vcell.getSpace(), + "EditBindings", true).getOrNewCell("d.1", 1); + if(ecur != null) { + binding = ZZDefaultSpace.findInheritableParam(ecur, id); + p("Tried by editbinds"); + if(binding == null && key != null && key.length() == 1) { + binding = ZZDefaultSpace.findInheritableParam(ecur, "INSERT"); + p("Tried by editbinds INSERT"); + } + if(binding == null) { + binding = ZZDefaultSpace.findInheritableParam(ecur, "DEFAULT"); + p("Tried by editbinds DEFAULT"); + } + } + } + + p("BINDING: "+binding); + if(binding != null) { + ZZCell bc = binding.s("d.1", 1); + p("Bind command cell: "+bc); + if(bc == null) { + System.out.println("AUGH! NO BINDING"); + return; + } + ZZCell nextstate = bc.h("d.3", -1, true); + if(nextstate != null) { + if(!isAppBind) + ZZCursorReal.set(getModeCursor(vcell), nextstate); + else + ApplitudeMgr.setAppBindsForWin(vcell, nextstate); + } + ZZCommand comm = null; + if(bc.getRootclone().s("d.xeq") == null) + comm = ZZCommand.getCommand(bc); + if(comm != null) + comm.execCallback( + target, + v, ctrl, + key, pt, xi + ); + else + new ZZPrimitiveActions().execCallback( + bc, + target, + v, ctrl, + key, pt, xi + ); + return; + } else if (key != null && key.equals("Esc")) { + v.getViewcell().getSpace().undo(); + } + } +} + diff --git a/Java/ZZKeyHacks.java b/Java/ZZKeyHacks.java new file mode 100644 index 0000000..49191eb --- /dev/null +++ b/Java/ZZKeyHacks.java @@ -0,0 +1,105 @@ +/* +ZZKeyHacks.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benja Fallenstein + */ +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; + +/** Hacks to work around Java's inconsistent, ideosyncratic key events. + * Everything in this class is static, but there are (static) variables + * for the "detected state of the system": e.g., how this Java VM handles + * umlauts. + *

    + * Currently, detects whether we get umlauts through KEY_PRESSED; if not, + * invokes them at KEY_TYPED. + */ + +public class ZZKeyHacks { +public static final String rcsid = "$Id: ZZKeyHacks.java,v 1.1.2.2 2001/04/08 15:17:51 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + static final void pa(String s) { ZZLogger.log(s); } + + // Java is really screwy about what keyevents get + // pressed and what are typed. We want to catch both. + + // It seems that at least on my platform and keybindings, + // this is the totally unreasonable but working way to get + // them. + + // Ouch. + + // FIXME: This is a REALLY REALLY BAD QUICK HACK to make the + // Finnish special letters work. The problem? We don't get a + // KEY_PRESSED for them. Damn Java! + + /** Whether we ever got an umlaut from a KEY_PRESSED event. + * If this is set to true, we ignore KEY_TYPED events. If it is set to + * false, KEY_TYPED events with umlauts in them get processed like + * KEY_PRESSED events. As KEY_PRESSED events occur before KEY_TYPED + * events, this is a gain. + */ + static boolean gotPressedUmlaut; + + /** The start of the Unicode character range we treat as umlauts. */ + static final int firstumlaut = 0x00C0; + + /** The end of the Unicode character range we treat as umlauts. */ + static final int lastumlaut = 0x00FD; + + /** Do the hacks on this key event. + * Currently, does the umlaut trick, as well as the testing whether we + * need it. + */ + static public KeyEvent keyEventHack(KeyEvent e) { + if(gotPressedUmlaut) return e; + + int id = e.getID(), c = e.getKeyChar(); + boolean umlaut = (c >= firstumlaut) && (c <= lastumlaut); + + if(!umlaut) return e; + + if(id == e.KEY_PRESSED) { + gotPressedUmlaut = true; + } else if(id == e.KEY_TYPED) { + return new KeyEvent(e.getComponent(), e.KEY_PRESSED, e.getWhen(), + e.getModifiers(), e.getKeyCode(), + e.getKeyChar()); + } + + return e; + } + + /** Reset the state, so as if the program was fired up anew. + * This sets back all information gathered about the Java VM so far + * and re-initializes the class. Currently this is used for testing + * purposes only: the TestUmlauts JUnit test suite needs to be able to + * run different tests emulating different kinds of VMs. + */ + static public void reset() { + gotPressedUmlaut = false; + } + + // Initialize the class by calling reset() a first time. + { reset(); } +} + diff --git a/Java/ZZLocalDimension.java b/Java/ZZLocalDimension.java new file mode 100644 index 0000000..884cf1c --- /dev/null +++ b/Java/ZZLocalDimension.java @@ -0,0 +1,89 @@ +/* +ZZLocalDimension.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** Dimension-centric implementation of a locally + * stored dimension. + */ +public class ZZLocalDimension extends ZZDimension { +public static final String rcsid = "$Id: ZZLocalDimension.java,v 1.14 2000/11/30 08:44:32 ajk Exp $"; + public static final boolean dbg = true; + final static void p(String s) { if(dbg) ZZLogger.log(s); } + final static void pa(String s) { ZZLogger.log(s); } + + /** Connections to the positive direction. */ + Hashtable cp = new Hashtable(); + /** Connections to the negative direction. */ + Hashtable cm = new Hashtable(); + + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + String s = c.id; + if(o != null) triggers.addObs(s, o); + if(steps>0) + while(steps-- > 0 && s != null) { + s = (String)cp.get(s); + if(o != null) triggers.addObs(s, o); + } + else + while(steps++ < 0 && s != null) { + s = (String)cm.get(s); + if(o != null) triggers.addObs(s, o); + } + + if(s==null) return null; + return (ZZCellHandle)space.getCellByID(s); + } + public void connect(ZZCellHandle c, ZZCellHandle d) { + disconnect(c, 1); + disconnect(d, -1); + /* XXX: This is from 0.3 branch, don't know if this + should be chosen instead of the above + if(cp.get(c.id) != null || + cm.get(d.id) != null) + throw new ZZConnectWouldBreakError("localdim"); + */ + cp.put(c.id, d.id); + cm.put(d.id, c.id); + triggers.chg(c.id); + triggers.chg(d.id); + } + public void disconnect(ZZCellHandle c, int dir) { + String o; + if(dir>0) { + o = (String)cp.get(c.id); + if(o!=null) { + cp.remove(c.id); + cm.remove(o); + } + } else { + o = (String)cm.get(c.id); + if(o!=null) { + cm.remove(c.id); + cp.remove(o); + } + } + triggers.chg(c.id); + } + +} diff --git a/Java/ZZLogger.java b/Java/ZZLogger.java new file mode 100644 index 0000000..f99bd54 --- /dev/null +++ b/Java/ZZLogger.java @@ -0,0 +1,83 @@ +/* +Main.java + * + * Copyright (c) 1999, 2000 Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho and Tuomas Lukka. + */ + +package org.gzigzag; +import java.lang.reflect.*; +import java.io.*; + +/** A static package for logging things into a file. + * Used for providing ZZ developers with debug output to help them + * solve crashes. + */ + +public class ZZLogger { + public static PrintWriter logfile = null; + + private static boolean syslog = false; + + public static void tryInitSyslog() { + try { + SysLogger.init(); + } catch (UnsatisfiedLinkError e) { + exc(e); + return; + } + syslog = true; + } + + public static void exc(Throwable t, String s) { + log(""+s); + exc(t); + } + + public static void exc(Throwable t) { + if(t instanceof InvocationTargetException) { + Throwable t1 = ((InvocationTargetException)t).getTargetException(); + verblog("InvokeException content: "); + exc(t1); + } + log(""+t); + t.printStackTrace(); + if(logfile != null) { + t.printStackTrace(logfile); + logfile.flush(); + } + } + + public static void log(String s) { + System.err.println(s); + if (syslog) SysLogger.log(s); + filelog(s); + } + + private static void filelog(String s) { + if (logfile != null) { + logfile.println(s); + logfile.flush(); + } + } + + public static void verblog(String s) { + if (syslog) SysLogger.verblog(s); + } +} diff --git a/Java/ZZModule.java b/Java/ZZModule.java new file mode 100644 index 0000000..960e167 --- /dev/null +++ b/Java/ZZModule.java @@ -0,0 +1,91 @@ +/* +ZZModule.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** An extension module implementing some Java functionality. + * Extension module classes should have a single static public member + * named module of this type. + *

    + * Clang commands implemented in extension modules are accessed + * through the Module.FUNCTION interface. + */ + +public abstract class ZZModule { +String rcsid = "$Id: ZZModule.java,v 1.14 2000/10/30 15:25:47 tjl Exp $"; + + /** Perform an action. + * For instance, if the action Foo.BAR is used in a cell, the method + * org.gzigzag.module.Foo.module.action("BAR",...) is called. + * @param id The name of the action. + * @param code The cell that the code was obtained from. + * @param target The cell that is the target of the action. Either the + * cell the cursor is on, or the cell that the user clicked + * on with the mouse. + * @param view The view the user activated this action from + * @param cview The control view associated + * @param key The event identifier + * @param pt The point clicked by the mouse + * @param xi The ZZScene describing the current contents of the window. + * May be used e.g. to draw XOR cursors. + */ + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + } + + /** Returns a ZOb for the given id. + * A cell parameter is not needed: since it's a ZOb, the caller must + * explicitly read them (and set the Component) after getting it. + * @see ZOb + */ + public ZOb newZOb(String id) { return null; } + + // Static routines for loading + + static Hashtable mods = new Hashtable(); + + /** Obtain the ZZModule object corresponding to the given string. + * This is the module member of the corresponding class. + */ + static public ZZModule getModule(String name) { + ZZModule m; + if((m= (ZZModule)mods.get(name)) == null) { + try { + Class clazz = Class.forName("org.gzigzag.module."+name); + m = + (ZZModule)clazz.getField("module").get(null); + } catch(Exception e) { + ZZLogger.exc(e); + ZZLogger.log("Error while loading module '"+name+"'"); + return null; + } + mods.put(name, m); + } + return m; + } + +} diff --git a/Java/ZZObs.java b/Java/ZZObs.java new file mode 100644 index 0000000..d4635f1 --- /dev/null +++ b/Java/ZZObs.java @@ -0,0 +1,36 @@ +/* +ZZObs.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +/** A simple class that observes something. + * This class cannot distinguish what caused the event - either + * the event has to be filtered prior to this or the whole thing reread + * in any case. + */ + +public interface ZZObs { +String rcsid = "$Id: ZZObs.java,v 1.11 2000/09/19 10:31:58 ajk Exp $"; + /** Called when something is changed. + */ + void chg(); +} diff --git a/Java/ZZObsTrigger.java b/Java/ZZObsTrigger.java new file mode 100644 index 0000000..a38e922 --- /dev/null +++ b/Java/ZZObsTrigger.java @@ -0,0 +1,196 @@ +/* +ZZObs.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, queuing and enable/disable by Rauli Ruohonen + */ + +package org.gzigzag; +import java.util.*; + +/** A class used to trigger ZZObses. + */ + +public class ZZObsTrigger { +String rcsid = "$Id: ZZObsTrigger.java,v 1.6.2.1 2001/04/08 16:13:59 ajk Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + // XXX Store weak references, not hard ones! + private static Vector allTrigs = new Vector(); + private static Hashtable obsQueue = new Hashtable(); + private static Hashtable obsDisabled = new Hashtable(); + + ZZObsTrigger() { + allTrigs.addElement(this); + } + + /** An object which keeps track of the observations of a single + * ZZObs. + */ + class Gob { + /** Linked list of Gobs, plus list of all objects that this + * Gob observes. + * This is a tricky part and this is also what makes us blazingly + * fast. And difficult to explain. + *

    + * First of all, there is a key for every object that this + * gob's obs has been addObs'ed for. + * The value depends on whether there are other gobs observing + * the same thing. If there are, then the hashtables form a linked + * list. If not, or if this is the last element of the linked + * list, the value in the Hashtable is this gob. + * That may seem odd until you realize that 1) hashtables can't + * store nulls, and 2) this is a pointer that is + * very likely to be in a register so fast to compare with + * the reference. + */ + Hashtable next = new Hashtable(); + /** The backward links. Only necessary links are stored. */ + Hashtable prev = new Hashtable(); + ZZObs obs; + } + + /** Key: ZZObs; Value: Gob. */ + Hashtable gobs = new Hashtable(); + + /** Key: Object (trigger); Value: Gob. */ + Hashtable trigs = new Hashtable(); + + + /** Called when something is changed. + * This call removes instances of the ZZObses triggered from + * all existing ZZObsTrigger objects. + */ + public synchronized void chg(Object o) { + Gob g,pg=null; + Hashtable next=trigs; + while((g = (Gob)next.get(o)) !=null && g!=pg) { + pg=g; + if(!chg(g.obs)) next=g.next; + } + // XXX This shouldn't be necessary! (views should use triggers) + ZZUpdateManager.chg(); + } + public static boolean chg(ZZObs obs) { + // XXX This shouldn't be necessary! (views should use triggers) + ZZUpdateManager.chg(); + synchronized(obsQueue) { + if(obsDisabled.containsKey(obs)) return false; + obsQueue.put(obs,obs); + for(int i=0; i only the + * event thread may call general ZZ structure -using code. + */ + public static void runObsQueue() { + p("runObsQueue enter"); + synchronized(obsQueue) { + while(obsQueue.size()>0) { + p("STARTTRIGSEQ "+(obsQueue.size())); + /* Trigger the queued observers in some order */ + Hashtable q=obsQueue; + obsQueue=new Hashtable(); + for(Enumeration e=q.keys();e.hasMoreElements();) + try { + ((ZZObs)e.nextElement()).chg(); + } catch(Exception ex) { + ZZLogger.exc(ex); + System.out.println("EXCEPTION WHILE TRIGGERING!"); + } + p("ENDTRIGSEQ "+(obsQueue.size())); + } + } + p("runObsQueue leave"); + } + + /** Enable/disable an observer. + * If an observer is disabled, chg(o) won't trigger it. chg(o) calls + * made before calling this method will be unaffected - that is, if + * obs is in obsQueue, it will be triggered whether it is enabled or not. + */ + public static void setEnabled(ZZObs obs,boolean t) { + if(t) obsDisabled.remove(obs); + else obsDisabled.put(obs,obs); + } +} diff --git a/Java/ZZPath.java b/Java/ZZPath.java new file mode 100644 index 0000000..2bc35ce --- /dev/null +++ b/Java/ZZPath.java @@ -0,0 +1,202 @@ + +/* +ZZPath.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/* Possibly publish this API later on? */ +interface PathOp { + /** Apply the pathop to the from cell, attaching the observer o + * to observe the relevant information about all the cells on the way. + * These objects do not need to attach observers to the from + * cell but all the others, including the last cell. + * @return null if the requested cell does not exist. + */ + ZZCell apply(ZZCell from, ZZObs o); +} + +/** A class to represent paths in the structure. + * It used to also be a notifier but that was changed: now it's just + * an abstract "path". + */ + +public class ZZPath { +public static final String rcsid = "$Id: ZZPath.java,v 1.26 2000/10/18 14:35:31 tjl Exp $"; + static public boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + PathOp[] arr = new PathOp[0]; + + public ZZPath() { } + + static final String drdim(ZZCell c) { + return ZZDefaultSpace.getPossDerefCell(c).getText(); + } + + static final int drdir(ZZCell c) { + String s = ZZDefaultSpace.getPossDerefCell(c).getText(); + if(s.equals("-")) return -1; + if(s.equals("+")) return +1; + return Integer.parseInt(s); + } + + static final String drtext(ZZCell c) { return drdim(c); } + + /** Creates a ZZPath from cells. + * The cells give the path through a simple format in d.1 and d.2: + * The first cell is the operation name, and then follow the + * parameters, just like in the other calls for this class. + *

    +	 * 	STEP  dim  n
    +	 *	HEAD dim dir
    +	 *	END dim dir
    +	 *	FIND dim dir str
    +	 * 
    + * Note that this is not automatically updated each time the path + * or the cursors in the path change - to be up to date, you need + * to create a new path each time. However, this is not such a + * time-consuming operation. + *

    + * "HEAD" is now deprecated in favor of "END". + */ + static public ZZPath createFromStructure1(ZZCell c) { + ZZPath p = new ZZPath(); + while(c!=null) { + ZZCell[] args = c.readRank("d.1", 1, false); + String s = c.getText(); + if(s.equals("STEP")) { + if(args.length < 2) + throw new ZZError("Not enough args for '"+s+"'"); + p = p.step(drdim(args[0]), drdir(args[1])); + } else if(s.equals("HEAD") || s.equals("END")) { + if(args.length < 2) + throw new ZZError("Not enough args for '"+s+"'"); + p = p.headcell(drdim(args[0]), drdir(args[1])); + } else if(s.equals("FIND")) { + if(args.length < 3) + throw new ZZError("Not enough args for '"+s+"'"); + p = p.untilstring(drdim(args[0]), + drdir(args[1]), drtext(args[2])); + } else { + throw new ZZError("ZZPath syntax: '"+s+"'"); + } + c = c.s("d.2", 1); + } + return p; + } + + /** Reads the structure through this path to obtain a cell. + * @param from The cell to start from + * @param error Whether not finding a cell is an error. + * This is for coder convenience: the message + * in the exception thrown is descriptive of + * where the not-found leg of the path was. + * @param o The observer to attach. + */ + public ZZCell readFrom(ZZCell from, boolean error, ZZObs o) { + if(from == null) + throw new ZZError("Can't read path from null!"); + ZZCell n = from; + for(int i=0; i + * Even worse, it is string-based: it doesn't hassle you about structure, + * it simply takes the string in the cell and executes a corresponding command. + *

    + * The one nifty thing is the module support: + * Given a function name like ZZMbox.FOO + * it will first dynamically load the class org.gzigzag.module.ZZMbox + * (this will later be probably xanadu.zz.module), and run its action + * routine (see ZZModule and ZZMbox docs for details). + */ + +public class ZZPrimitiveActions implements ZZExec { +public static final String rcsid = "$Id: ZZPrimitiveActions.java,v 1.141.2.8 2002/03/05 18:21:50 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + static final void pa(String s) { ZZLogger.log(s); } + public ZZPrimitiveActions() {} + + public static java.io.PrintWriter textlog; + + ZZCell findPar(ZZCell view, String param) { + ZZCell cur = view.s("d.2", 1); + while(cur!=null) { + if(cur.getText().equals(param)) + return cur.s("d.1", 1); + cur = cur.s("d.2", 1); + } + return null; + } + int getDimstrAsInt(String param) { + if(param.equals("X")) return 0; + else if(param.equals("Y")) return 1; + else if(param.equals("Z")) return 2; + return -1; + } + String getDim(ZZCell view, String param) { + ZZCell c = findPar(view, param); + if(c!=null) + return c.getText(); + int ind=getDimstrAsInt(param); + + return ZZDefaultSpace.getDimList(view)[ind]; + } + String D(ZZCell view, String param) { + return getDim(view, param); + } + + void exchangeCells(ZZCell view1, ZZCell view2) { + String[] ds1 = ZZDefaultSpace.getDimList(view1); + String[] ds2 = ZZDefaultSpace.getDimList(view2); + Hashtable ds = new Hashtable(); + ds.put(ds1[0], ds1[0]); + ds.put(ds1[1], ds1[1]); + ds.put(ds2[0], ds2[0]); + ds.put(ds2[1], ds2[1]); + ZZCell c1 = ZZCursorReal.get(view1); + ZZCell c2 = ZZCursorReal.get(view2); + for(Enumeration e = ds.keys(); + e.hasMoreElements(); ) { + String d = (String)e.nextElement(); + ZZCell n1 = c1.s(d, -1); c1.disconnect(d, -1); + ZZCell n2 = c2.s(d, -1); c2.disconnect(d, -1); + if(n2 != null) c1.connect(d, -1, n2); + if(n1 != null) c2.connect(d, -1, n1); + n1 = c1.s(d, 1); c1.disconnect(d, 1); + n2 = c2.s(d, 1); c2.disconnect(d, 1); + if(n2 != null) c1.connect(d, 1, n2); + if(n1 != null) c2.connect(d, 1, n1); + } + } + + // Set view cursor + void svc(ZZCell view, ZZCell to) { + if(to == null || view == null) return; + ZZCursorReal.set(view, to); + } + + ZZCell findOtherView(ZZCell view) { + ZZCell oth = view.s("d.ctrlview", -1); + if(oth == null) + oth = view.s("d.ctrlview", 1); + if(oth == null) { + System.out.println("CNCTPAIR OTHER NOT FOUND"); + } + return oth; + } + + /** Move the cursor. + * @return Whether a timestamp would be reasonable. + */ + boolean move(ZZCell view, ZZCell viewCursor, String vdim, int dir, + ZZCell realView, ZZCell realCtrl) { + if ( viewCursor == null ) return false; + String[] ss = ZZDefaultSpace.getDirActionWaitingAndClear(view); + if(ss!=null) { + String s = ss[0]; + if(s.equals("CNCTI")) { + cnct(view, viewCursor, true, vdim, dir); + } else if(s.equals("NEW")) { + viewCursor.N(vdim, dir); +// } else if(s.equals("NEWANDEDIT")) { +// svc(view, viewCursor.N(vdim, dir)); +// switchcursmode(view); +// XXX Problem: this doesn't switch keybindings mode + } else if(s.equals("EXCISE")) { + viewCursor.excise(vdim); + } else if(s.equals("DISC")) { + viewCursor.disconnect(vdim, dir); + } else if(s.equals("HOP")) { + viewCursor.hop(vdim, dir); + } else if(s.equals("CLONE")) { + ZZCell clone = ZZCursorReal.get(realView).zzclone(); + viewCursor.insert(vdim, dir, clone); + } else if(s.equals("CLONECTRL")) { + ZZCell clone = ZZCursorReal.get(realCtrl).zzclone(); + viewCursor.insert(vdim, dir, clone); + } else if(s.equals("CNCTPAIR")) { + smartconnect(viewCursor, vdim, dir, ZZCursorReal.get( + findOtherView(view))); + } else if(s.equals("CNCTC")) { + cnctcln(view, viewCursor, true, vdim, dir); + } else if(s.equals("CNCT")) { + cnct(view, viewCursor, false, vdim, dir); + } else if(s.equals("SORTALPH")) { + ZZUtil.sortRank(viewCursor, vdim, dir, + new ZZUtil.Comparator() { + public int compare(ZZCell c1, ZZCell c2) { + return c1.getText().compareTo(c2.getText()); + } + }, true); + } else if(s.equals("END")) { + svc(view, viewCursor.h(vdim, dir)); + } else if(s.equals("MONOCHUG")) { + if(ss[1] == null || ss[1].equals("")) { + p("Move: "+s+" "+vdim+" "+dir); + ZZDefaultSpace.storeDirActionWaiting(view, s); + ZZDefaultSpace.storeDirWaiting(view, vdim, dir); + return false; + } + // monochug operation + int ddir = (ss[2].equals("+") ? 1 : -1); + String ddim = ss[1]; + ZZCell targ = viewCursor.s(ddim, ddir); + if(targ == null) return false; + targ = targ.s(vdim, dir); + if(targ == null) return false; + if(targ.s(ddim, -ddir) != null) + return false; + viewCursor.disconnect(ddim, ddir); + viewCursor.connect(ddim, ddir, targ); + } else if(s.equals("FINDTEXT")) { + String tf = ZZDefaultSpace.getInbuf(view.getSpace(), false); + if(tf == null || tf.equals("")) return false; + for(ZZCell c = viewCursor.s(vdim, dir); + c != null && c != viewCursor; + c = c.s(vdim, dir)) { + if(c.getText().indexOf(tf) >= 0) { + svc(view, c); + return true; + } + } + } + return true; + } else { + String s = ZZDefaultSpace.getInbuf(view.getSpace(), true); + /* + * * DO NOT DO IT. TOO CONFUSING FOR USERS. + if(s != null && !s.equals("")) { + ZZCell c = view.getSpace().getCellByID(s); + if(c == null) { + throw new ZZError("No such cell: '"+s+"'..."); + } + smartconnect(viewCursor, vdim, dir, c); + } + */ + svc(view, viewCursor.s(vdim, dir)); + // Do timestamp: it's a motion. + return true; + } + } + +// or only mark, if ... + void mrkmv(ZZCell v, ZZCell vc, String dim, int dir) { + // New way: in the view + synchronized(v.getSpace()) { + ZZCell m = v.s("d.mark", 1); + boolean had = false; + ZZCell m0 = v; + while(m!=null) { + if(m.h("d.mark-set",-1) + ==vc) { had = true; break; } + m0 = m; + m = m.s("d.mark", 1); + } + if(had) { + // Delete the whole relation cell. + // The ranks collapse around it just right. + m.delete(); + } else { + ZZCell mark = vc.N("d.mark-set", 1); + m0.connect("d.mark", mark); + } + } + if(dim != null && dir != 0) + move(v, vc, dim, dir, null, null); + } + + // XXX Combine the following two. + // Connect + void cnct(ZZCell v, ZZCell vc, boolean inclCurs, String dim, int dir) { + // Also clears mark. + ZZCell[] cs; + synchronized(v.getSpace()) { + cs = ZZDefaultSpace.getMark(v); + ZZDefaultSpace.clearMark(v); + ZZCell cur = (inclCurs ? vc : null); + for(int i=0; i 1) { + if(toks[1].equals("CTRL")) { usec=true; } + + if(toks[1].equals("+")) { dx=null; dir = 1; } + if(toks[1].equals("-")) { dx=null; dir = -1; } + + if(toks[1].equals("C+")) { dx=null; dir = 1; usec=true; } + if(toks[1].equals("C-")) { dx=null; dir = -1; usec=true; } + + if(toks[1].equals("X+")) { dx="X"; dir = 1; } + if(toks[1].equals("X-")) { dx="X"; dir = -1; } + if(toks[1].equals("Y+")) { dx="Y"; dir = 1; } + if(toks[1].equals("Y-")) { dx="Y"; dir = -1; } + if(toks[1].equals("Z+")) { dx="Z"; dir = 1; } + if(toks[1].equals("Z-")) { dx="Z"; dir = -1; } + + if(toks[1].equals("X")) { dx="X"; dir = 0; } + if(toks[1].equals("Y")) { dx="Y"; dir = 0; } + if(toks[1].equals("Z")) { dx="Z"; dir = 0; } + + if(toks[1].equals("CX+")) { dx="X"; dir = 1; usec=true; } + if(toks[1].equals("CX-")) { dx="X"; dir = -1; usec=true; } + if(toks[1].equals("CY+")) { dx="Y"; dir = 1; usec=true; } + if(toks[1].equals("CY-")) { dx="Y"; dir = -1; usec=true; } + if(toks[1].equals("CZ+")) { dx="Z"; dir = 1; usec=true; } + if(toks[1].equals("CZ-")) { dx="Z"; dir = -1; usec=true; } + + if(toks[1].equals("T0+")) { sndedge = 0; dir = 1; } + if(toks[1].equals("T0-")) { sndedge = 0; dir = -1; } + if(toks[1].equals("T1+")) { sndedge = 1; dir = 1; } + if(toks[1].equals("T1-")) { sndedge = 1; dir = -1; } + } + + if(usec && ctrlView == null) { + callbackFailed(c, "NO CONTROL VIEW"); + ZZDefaultSpace.getDirActionWaitingAndClear(dataView); + // Do not timestamp taking the operation out, either, + // because putting it in was not stamped. + // XXX Some strange bug? + code.getSpace().stamp(); + return; + } + + if(!usec) { + view = dataView; + otherView = ctrlView; + viewCursor = dataCursor; + zzv = zzdv; + } else { + view = ctrlView; + otherView = dataView; + viewCursor = ctrlCursor; + zzv = zzcv; + } + + if(dx != null) + vdim = D(view, dx); + if(target != null) + viewCursor = target; + + ZZCell coderoot = code.getRootclone(); + if(coderoot.s("d.xeq") != null) { + org.gzigzag.flowing.FlowingClang.run + (coderoot, new Data(ctrlView, dataView, key), false); + } else if(toks[0].equals("NEW") || + toks[0].equals("NEWANDEDIT") || + toks[0].equals("EXCISE") || + toks[0].equals("DISC") || + toks[0].equals("CNCTI") || + toks[0].equals("CNCTPAIR") || + toks[0].equals("CLONE") || + toks[0].equals("CLONECTRL") || + toks[0].equals("CNCT") || + toks[0].equals("CNCTC") || + toks[0].equals("HOP") || + toks[0].equals("MONOCHUG") || + toks[0].equals("SORTALPH") || + toks[0].equals("FINDTEXT") || + toks[0].equals("END")) { + + // XXX Should this be implemented differently, so that the + // dir doesn't need to be stored in the structure? + ZZDefaultSpace.storeDirActionWaiting(view, toks[0]); + dontClearAction = true; + if (dx != null) { + move(view, viewCursor, vdim, dir, dataView, ctrlView); + // Move has commands that take more than one dir. + } else { + dontStamp = true; + } + } else if(toks[0].equals("CRSR")) { + dontStamp = + ! move(view, viewCursor, vdim, dir, dataView, ctrlView); + // Move has commands that take more than one dir. + dontClearAction = true; + } else if(toks[0].equals("EXCHANGECELLS")) { + exchangeCells(dataView, ctrlView); + } else if(toks[0].equals("ORIGINAL")) { + svc(view, viewCursor.h("d.clone", -1)); + } else if(toks[0].equals("NEXTCLONE")) { + ZZCell foo = viewCursor.s("d.clone", 1); + if(foo != null) svc(view, foo); + } else if(toks[0].indexOf("MOUSE") == 0) { + Object ob = xi.getObjectAt(pt.x, pt.y); + ZZCursor cc=null; + ZZCell cell=null; + + if(ob instanceof ZZCursor) { + cc = (ZZCursor)ob; + cell=cc.get(); + } else if(ob instanceof ZZCell) { + cell=(ZZCell)ob; + } else return; + if(cell==null) return; + + if(toks[0].equals("MOUSESETC")) { + svc(view, cell); + fastany = false; + } + else if(toks[0].equals("MOUSESETCTXT")) { + if(cc==null) return; + svc(view, cell); + ZZCursorReal.setOffs(view, cc.getOffs()); + fastany = false; + } + else if(ctrlCursor!=null && c.equals("MOUSEEXEC")) { + pa("MOUSEEXEC"); + this.execCallback(ctrlCursor, cell, + zzv, zzcv, null, null, null); + + } + else if(toks[0].equals("MOUSEMARK")) { + mrkmv(view, cell, null, 0); + fastany = false; + } else if(toks[0].equals("MOUSESETDIMOTHER")) { + setdim(otherView, dx, cell); + } else { + callbackFailed(c, "Unknown MOUSE code"); + return; + } + } + else if(ctrlCursor!=null && c.equals("EXEC")) { + // This is an interesting one: it just means "execute + // whatever cell is visible in the control view. + // So we call ourselves... + // XXX inherit xi really? + ZZCommand comm = ZZCommand.getCommand(ctrlCursor); + if(comm != null) + comm.execCallback(viewCursor, + zzdv, zzcv, null, pt, xi); + else + this.execCallback(ctrlCursor, viewCursor, + zzdv, zzcv, null, pt, xi); + } + else if(c.equals("HERA1")) { + // Execute the first, primitive calling sequence of + // a Heraclitus Clang primitive poswards on d.2 from + // the command cell + ZZCell hc = code.s("d.2", 1); + if(hc == null) throw new ZZError("No heraclitus1 prim!"); + ZZCell curspar = code.N(); + ZZCell curs1 = code.N(); + ZZCell curs2 = curs1.N("d.1", 1); + ZZCursorReal.set(curs1, ctrlView); + ZZCursorReal.set(curs2, dataView); + ZZCursorReal.set(curspar, curs1); + try { + p("Enter heraclitus: "); + org.gzigzag.heraclitus.HeraclitusClang.execute( + hc, curspar); + p("Exit heraclitus"); + } finally { + ZZCursorReal.delete(curs1); + ZZCursorReal.delete(curs2); + ZZCursorReal.delete(curspar); + curs1.delete(); + curs2.delete(); + curspar.delete(); + } + } + + else if(toks[0].equals("MARK")) + mrkmv(view, viewCursor, dx, dir); + else if(toks[0].equals("DIM")) + chugdim(view, dx, dir); + else if(toks[0].equals("SETDIMS")) + setdims(view, viewCursor); + else if(toks[0].equals("RASTER")) + hopraster(view, dir!=0 ? dir : 1); + else if(toks[0].equals("FFACTORY")) + hopffactory(view, dir!=0 ? dir : 1); + else if(toks[0].equals("HOME")) { + ZZCell home = view.getSpace().getHomeCell(); + svc(view, home); + } + else if(toks[0].equals("HOMECLR")) { + ZZCell home = view.getSpace().getHomeCell(); + ZZCell datarec = ZZDefaultSpace + .findInheritableParam(dataView, "CursorRecovery"); + if(datarec!=null) ZZCursorReal.attach(dataView, datarec); + ZZCell ctrlrec = ZZDefaultSpace + .findInheritableParam(ctrlView, "CursorRecovery"); + if(ctrlrec!=null) ZZCursorReal.attach(ctrlView, ctrlrec); + svc(dataView, home); + svc(ctrlView, home); + ZZCell dimlist = + ZZDefaultSpace.findDefaultDimlist(home); + setdims(dataView, dimlist); + setdims(ctrlView, dimlist); + + ZZDefaultSpace.clearMark(dataView); + + } else if(toks[0].equals("DELETESCRAM")) { + ZZCell mv = null; + mv = viewCursor.s(D(view, "X"), -1); + if(mv == null) + mv = viewCursor.s(D(view, "X"), +1); + if(mv == null) + mv = viewCursor.s(D(view, "Y"), -1); + if(mv == null) + mv = viewCursor.s(D(view, "Y"), +1); + if(mv == null) + mv = viewCursor.s(D(view, "Z"), -1); + if(mv == null) + mv = viewCursor.s(D(view, "Z"), +1); + if(mv == null) + mv = view.getSpace().getHomeCell(); + svc(view, mv); + viewCursor.delete(); + } + + else if(toks[0].equals("QUIT")) { + // Commit changes to space here + viewCursor.getSpace().commit(); + SafeExit.exit(0); + } + else if(toks[0].equals("APPENDINPUT")) { + if(key != null && key.length() == 1) + ZZDefaultSpace.appendInbuf(viewCursor.getSpace(), key); + dontStamp = true; + } else if(toks[0].equals("BACKSPACEINPUT")) { + ZZDefaultSpace.appendInbuf(viewCursor.getSpace(), null); + dontStamp = true; + } else if(toks[0].equals("CLRINPUT")) { + ZZDefaultSpace.getInbuf(viewCursor.getSpace(), true); + dontStamp = true; + } else if(toks[0].equals("GOTO")) + do_goto(view); + + // Sound span adjustment. These will be useful + // in a more general way later on. + else if(toks[0].equals("SNDL")) { + Span sp = viewCursor.getSpan(); + ZZCell n = viewCursor.s("d.2", sndedge*2-1); + Span nsp = n.getSpan(); + if(sp!=null && nsp!=null) { + Span[] sps; + if(sndedge==0) { + sps = nsp.adjustEdgeLocked(100000000*dir, sp, 500000000); + n.setSpan(sps[0]); + viewCursor.setSpan(sps[1]); + } else { + sps = sp.adjustEdgeLocked(100000000*dir, nsp, 500000000); + viewCursor.setSpan(sps[0]); + n.setSpan(sps[1]); + } + } else if(sp!=null) + viewCursor.setSpan( + sp.adjustEdge(sndedge, 100000000 * dir)); + } else if(toks[0].equals("SNDS")) { + Span sp = viewCursor.getSpan(); + + if(sp!=null) + viewCursor.setSpan( + sp.adjustEdge(sndedge, 100000000 * dir)); + } else if(toks[0].equals("SNDSPLIT")) { + ZZCell n = viewCursor.N("d.2", 1); + Span sp = viewCursor.getSpan(); + if(sp!=null) { + Span[] sps = sp.splitInHalf(); + viewCursor.setSpan(sps[0]); + n.setSpan(sps[1]); + } + } else if(toks[0].equals("SNDJOIN+")) { + ZZCell o = viewCursor.s("d.2", 1); + if(o!=null) { + Span sp1 = viewCursor.getSpan(); + Span sp2 = o.getSpan(); + if(sp1!=null && sp2!=null) { + Span spj = sp1.join(sp2, 500000000); + if(spj!=null) { + viewCursor.setSpan(spj); + // XXX ??? Try to absorb links? + o.delete(); + } + } + } + } else if(toks[0].equals("SWAPCRSR")) { + ZZCell view2 = findOtherView(view); + ZZCell view2c = ZZCursorReal.get(view2); + svc(view, view2c); + svc(view2, viewCursor); + } else if(toks[0].equals("FETCH")) { + svc(findOtherView(view), viewCursor); + } else if(toks[0].equals("PUICOPY")) { + ZZUtil.puiCopy(viewCursor); + } else if(toks[0].equals("PUIPASTE")) { + ZZUtil.puiPaste(viewCursor); + } else if(toks[0].equals("PUICOPYLINE")) { // Copy along y-dim + ZZUtil.puiCopy(viewCursor, ZZCursorReal.get( + dataView.s("d.dims", 1) + .s("d.dims", 1) + ).getText()); + } else if(toks[0].equals("PUICOPYRANK")) { // Copy along y-dim + // insert \n between + // cells + ZZUtil.puiCopyRank(viewCursor, ZZCursorReal.get( + dataView.s("d.dims", 1) + .s("d.dims", 1) + ).getText()); + } else if(toks[0].equals("TXTINSERT")) { + // XXX ??? + p("Txtins: '"+key+"'"); + CharScroll cs = (CharScroll) + Scroll.obtain(viewCursor.getSpace(), + "textinput"); + long offs = cs.curEnd(); + cs.append(key); + long offs2 = cs.curEnd()-1; + VStream.insert(new ZZCursorReal(view), + Span.create( + Address.scrollOffs(cs, offs), + Address.scrollOffs(cs, offs2) + ) + ); + } else if(toks[0].equals("SWITCHCURSMODE")) { + switchcursmode(view); + dontStamp = true; + } else if(toks[0].equals("SWITCHOFFCURSMODE")) { + switchcursmodeoff(view); + } else if(toks[0].equals("CTXTHOME")) { + if (ZZCursorReal.getOffs(view) == ZZCursorReal.NO_OFFSET) return; + ZZCursorReal.setOffs(view, 0); + dontStamp = true; + } else if(toks[0].equals("CTXTEND")) { + if (ZZCursorReal.getOffs(view) == ZZCursorReal.NO_OFFSET) return; + ZZCursorReal.setOffs(view, viewCursor.getText().length()); + dontStamp = true; } else if(toks[0].equals("CTXTSOL")) { // SOL = start of line + if (ZZCursorReal.getOffs(view) == ZZCursorReal.NO_OFFSET) return; + int cur = ZZCursorReal.getOffs(view); + String line = viewCursor.getText(); + if (cur >= line.length()) cur = line.length()-1; + if (line.charAt(cur) == '\n') --cur; + for (int i = cur; i >= 0; --i) { + p("seeking SOL: charAt = " + line.charAt(i)); + if (line.charAt(i) == '\n') { + cur = i+1; + break; + } + if (i == 0) { + cur = i; + break; + } + } + if (cur > line.length()) cur = line.length(); + if (cur < 0) cur = 0; + ZZCursorReal.setOffs(view, cur); + dontStamp = true; + } else if(toks[0].equals("CTXTEOL")) { // EOL = start of line + if (ZZCursorReal.getOffs(view) == ZZCursorReal.NO_OFFSET) return; + int cur = ZZCursorReal.getOffs(view); + String line = viewCursor.getText(); + for (int i = cur; i < line.length(); ++i) { + if (line.charAt(i) == '\n') { + cur = i; + break; + } + if (i == line.length() - 1) { + cur = line.length(); + break; + } + } + if (cur > line.length()) cur = line.length(); + if (cur < 0) cur = 0; + ZZCursorReal.setOffs(view, cur); + dontStamp = true; + } else if(toks[0].equals("CTXTCRSR")) { + int cur = ZZCursorReal.getOffs(view); + if(cur == ZZCursorReal.NO_OFFSET) return; + cur += dir; + if(cur < 0) cur = 0; + if(cur > viewCursor.getText().length()) + cur = viewCursor.getText().length(); + ZZCursorReal.setOffs(view, cur); + dontStamp = true; + } else if(toks[0].equals("VSTRMCRSR")) { + if(ZZCursorReal.getOffs(view) == ZZCursorReal.NO_OFFSET) + throw new ZZError("Need cursor offset"); + + if(!Stream.move( + new ZZCursorReal(view), + VStream.dim, + dir)) { + callbackFailed("VSTRMCRSR", "nothing there"); + } else { + fastany = false; + } + + dontStamp = true; + } else if(toks[0].equals("VSTRMJUMP")) { + int offs = ZZCursorReal.getOffs(view); + String txt = viewCursor.getText(); + ZZCell next = viewCursor.s("d.2", dir!=0 ? dir : 1); + + offs = dir >= 0 ? txt.indexOf(' ', offs) + : txt.lastIndexOf(' ', offs - 1); + if(offs > -1) + ZZCursorReal.setOffs(view, offs + (dir<0 ? 0 : 1)); + else if(next != null) { + svc(view, next); + ZZCursorReal.setOffs(view, + dir<0 ? next.getText().length() : 0); + } else + ZZCursorReal.setOffs(view, dir<0 ? 0 : txt.length() - 1); + dontStamp = true; + } else if(toks[0].equals("VSTRMSPLIT")) { + ZZCell next = viewCursor.N("d.2", dir!=0 ? dir : 1); + if(viewCursor.getSpan() == null) { + int offs = ZZCursorReal.getOffs(view); + String txt = viewCursor.getText(); + String one = txt.substring(0, offs), + two = txt.substring(offs); + if(dir >= 0) { + viewCursor.setText(one); next.setText(two); + } else { + viewCursor.setText(two); next.setText(one); + } + } // XXX Split spans, too + ZZCursorReal.setOffs(view, 0); + svc(view, next); + dontStamp = true; + } else if(toks[0].equals("CTXTINSERT") || + toks[0].equals("CTXTBKSP") || + toks[0].equals("CTXTDEL")) { + dontStamp = true; + if(viewCursor.getSpan() != null) { + System.out.println("Can't modify span"); + return; + } + int cur = ZZCursorReal.getOffs(view); + // Make sure it fits. + if(cur > viewCursor.getText().length()) + cur = viewCursor.getText().length(); + if(cur == ZZCursorReal.NO_OFFSET) return; + StringBuffer s = new StringBuffer(viewCursor.getText()); + if(toks[0].equals("CTXTINSERT")) { + p("CTXTINSERT: key = " + key); + String ik = key; + if (ik != null && ik.equals("Enter")) ik = "\n"; + // Don't insert e.g. "Shift" + if(ik != null && ik.length() == 1) { + if(textlog != null) { + textlog.print(ik); + // flush all the time so nothing is lost + // in a crash + textlog.flush(); + } + s.insert(cur, ik); + cur += 1; + } + } else if(toks[0].equals("CTXTBKSP")) { + if(cur > 0) { + String str = s.toString(); + // XXX delete requires JDK 1.2 + s = new StringBuffer( str.substring(0, cur-1) ); + s.append(str.substring(cur)); + + cur -= 1; + } + } else if(toks[0].equals("CTXTDEL")) { + if(cur < viewCursor.getText().length()) { + String str = s.toString(); + s = new StringBuffer( str.substring(0, cur) ); + s.append(str.substring(cur+1)); + } + } + viewCursor.setText(s.toString()); + ZZCursorReal.setOffs(view, cur); + } else if(toks[0].equals("CURSEL")) + cursel(view, dir, false); + else if(toks[0].equals("SELEVATE")) + cursel(view, dir, true); + else if(toks[0].equals("CreateCursors")) { + ZZCell h = view.getSpace().getHomeCell(); + ZZCell sc = ZZDefaultSpace + .findOnSystemlist(view.getSpace(), "SysCursors", false); + if(sc != null) { + ZZDefaultSpace.newSysCursor(sc, h, Color.blue.brighter()); + ZZDefaultSpace.newSysCursor(sc, h, Color.yellow.darker()); + ZZDefaultSpace.newSysCursor(sc, h, Color.red.darker()); + ZZDefaultSpace.newSysCursor(sc, h, new Color(180, 0, 255)); + } else + callbackFailed(c, "SysCursors list required"); + } else if(toks[0].equals("NEWVIEWS")) { + // Create a new view pair. + ZZDefaultSpace.newViewPair(view.getSpace()); + } else if(toks[0].equals("EDITVIEW") || toks[0].equals("HELP")) { + boolean help = toks[0].equals("HELP"); + ZZCell home = dataView.getSpace().getHomeCell(); + ZZCell rl = home.findText("d.2", 1, "AllViews"); + rl = rl.s("d.1", 1); + rl = rl.findText("d.2", 1, "Edit"); + if (rl == null) throw new ZZError("Edit view not found"); + rl = rl.getOrNewCell("d.clone", 1); + ZZCell cursCell; + if(help) { + cursCell = home.N(); + ZZCursorReal.set(cursCell, + viewCursor.getOrNewCell("d.help", 1)); + } else + cursCell = dataView; + + ZZCell win = ZZDefaultSpace.newToplevelView(dataView.getSpace(), + help ? "Help" : "Edit", + help ? 100 : 512, help ? 100 : 449, + help ? 400 : 512, help ? 400 : 100, + rl, null, // XXX Defaultbind? + null, cursCell, + null, + Color.white); // XXX PREFERENCE!!! + } else if(toks[0].equals("EDITHACK")) { + new ZZTextView(view); + } else if(toks[0].equals("APPLITUDE")) { + ApplitudeMgr.rotateWindowApp(view, dir); + } else if(toks[0].equals("GETSPACEID")) { + target.setText(target.getSpace().getID()); + } else if(toks[0].equals("SETSPACEID")) { + target.getSpace().setID(target.getText()); + } else if(toks[0].equals("UPDATEWINS")) { + ZZWindows.update(); + } else if(toks[0].equals("ACCURSE")) { + // Make the cell accursed in the other window a cursor to the + // cell accursed in window for which the action occured. + ZZCursorReal.set(ZZCursorReal.get(otherView), viewCursor); + } else if(toks[0].equals("UNDO")) { + code.getSpace().undo(); + dontStamp = true; + } else if(toks[0].equals("REDO")) { + code.getSpace().redo(); + dontStamp = true; + } else if(toks[0].equals("COMMIT")) { + code.getSpace().commit(); + } + else + callbackFailed(c, "UNKNOWN CODE"); + + p("ZZPrimitiveActions: postlude: "+fastany+" "+zzv+" "+ + dontClearAction); + + if(fastany) + ZZUpdateManager.setFast(zzv); + + // Clear the waiting dir action + if(!dontClearAction) + ZZDefaultSpace.getDirActionWaitingAndClear(view); + + if(!dontStamp) + code.getSpace().stamp(); + } + } + + static ZZCell addAct(ZZCell s, String name, String act) { + ZZCell n1 = s.N("d.2", 1); + n1.setText(name); + ZZCell n2 = n1.N("d.1", 1); + n2.setText(act); + return n2; + } + + static void addAct(ZZCell s, String name, String act, ZZCell after) { + ZZCell c = addAct(s, name, act); + after.insert("d.3", 1, c); + } + + static void setModeColor(ZZCell mode, Color col) { + if(col == null) { + if(mode.s("d.color") != null) + mode.disconnect("d.color", 1); + } else { + ZZCell c = mode.getOrNewCell("d.color", 1); + c.setText(String.valueOf(col.getRGB())); + } + } + + /** Puts a number of default key bindings to the structure. + * ZZKeyBindings1 structure is assumed (list on d.2 of keys + * and on d.1 the responses) + */ + static public void putDefBinds(ZZCell start, ZZCell editstart) { + start.setText("Normal mode"); + editstart.setText("Text edit bindings"); + + // Apparently, this wasn't actually necessary! + /* + ZZCell dir = start.N("d.2", 1); + dir = dir.N("d.3", -1); + dir.setText("Motion"); + */ + ZZCell dir = start; + + ZZCell editmode = start.N("d.1", 1); + setModeColor(editmode, Color.white); + + editmode.setText("Edit mode"); + editmode.N("d.2").setText("EDITBINDS"); + addAct(editmode, "Tab", "SWITCHOFFCURSMODE", dir); + addAct(editmode, "Esc", "SWITCHOFFCURSMODE", dir); + + ZZCell curs = editstart; + curs.setText("Text edit mode"); + addAct(curs, "Ctrl-A", "CTXTSOL"); + addAct(curs, "Ctrl-E", "CTXTEOL"); + addAct(curs, "End", "CTXTEND"); + addAct(curs, "Home", "CTXTHOME"); + addAct(curs, "Right", "CTXTCRSR +"); + addAct(curs, "Left", "CTXTCRSR -"); + addAct(curs, "Backspace", "CTXTBKSP"); + addAct(curs, "Delete", "CTXTDEL"); + addAct(curs, "MouseClicked1", "MOUSESETCTXT"); + addAct(curs, "DEFAULT", "CTXTINSERT"); + + + ZZCell cursel = editmode.N("d.1", 1); + cursel.setText("Cursel mode"); + cursel.N("d.color").setText("CURSOR"); + + addAct(cursel, " ", "", dir); + addAct(cursel, "Esc", "", dir); + addAct(cursel, "Alt-C", "", dir); + addAct(cursel, "Left", "CURSEL -"); + addAct(cursel, "Right", "CURSEL +"); + addAct(cursel, "Up", "SELEVATE -"); + addAct(cursel, "Down", "SELEVATE +"); + + addAct(cursel, "j", "CURSEL -"); + addAct(cursel, "l", "CURSEL +"); + addAct(cursel, "i", "SELEVATE -"); + addAct(cursel, ",", "SELEVATE +"); + + addAct(cursel, "s", "CURSEL C-"); + addAct(cursel, "f", "CURSEL C+"); + addAct(cursel, "e", "SELEVATE C-"); + addAct(cursel, "c", "SELEVATE C+"); + + // Quote starts insert buffer mode... + ZZCell bufins = cursel.N("d.1", 1); + bufins.setText("Quotebuf"); + setModeColor(bufins, Color.pink); + + addAct(bufins, "DEFAULT", "APPENDINPUT"); + addAct(bufins, "Backspace", "BACKSPACEINPUT"); + addAct(bufins, "\"", "", dir); + addAct(bufins, "Esc", "", dir); + + // Totally temporary + addAct(dir, "Tab", "SWITCHCURSMODE", editmode); + addAct(dir, "Alt-C", "", cursel); + + addAct(dir, "\"", "CLRINPUT", bufins); + + addAct(dir, "l", "CRSR X+"); + addAct(dir, "j", "CRSR X-"); + addAct(dir, "i", "CRSR Y-"); + addAct(dir, ",", "CRSR Y+"); + addAct(dir, "k", "CRSR Z+"); + addAct(dir, "K", "CRSR Z-"); + + // Caps locked + addAct(dir, "L", "CRSR X+"); + addAct(dir, "J", "CRSR X-"); + addAct(dir, "I", "CRSR Y-"); + + addAct(dir, "a", "MONOCHUG"); + + addAct(dir, "f", "CRSR CX+"); + addAct(dir, "s", "CRSR CX-"); + addAct(dir, "e", "CRSR CY-"); + addAct(dir, "c", "CRSR CY+"); + addAct(dir, "d", "CRSR CZ+"); + addAct(dir, "D", "CRSR CZ-"); + + // Caps locked + addAct(dir, "F", "CRSR CX+"); + addAct(dir, "S", "CRSR CX-"); + addAct(dir, "E", "CRSR CY-"); + addAct(dir, "C", "CRSR CY+"); + + addAct(dir, "Right", "CRSR X+"); + addAct(dir, "Left", "CRSR X-"); + addAct(dir, "Up", "CRSR Y-"); + addAct(dir, "Down", "CRSR Y+"); + + addAct(start, "Ctrl-C", "PUICOPY"); + addAct(start, "Ctrl-Shift-C", "PUICOPYLINE"); + addAct(start, "Ctrl-Alt-C", "PUICOPYRANK"); + addAct(start, "Ctrl-V", "PUIPASTE"); + + addAct(start, "-", "CNCTI" /*, dir */); + addAct(start, "n", "NEW" /*, dir */); + // XXX Problem: must switch to edit mode AFTER arrow + // addAct(start, "N", "NEWANDEDIT", editmode); + addAct(start, "b", "DISC" /*, dir */); + addAct(start, "/", "CNCTPAIR" /*, dir */); + addAct(start, "t", "CLONE" /*, dir */); + addAct(start, "T", "CLONECTRL" /*, dir */); + addAct(start, "o", "ORIGINAL"); + addAct(start, "O", "ORIGINAL CTRL"); + addAct(start, "Alt-O", "NEXTCLONE"); + addAct(start, "Alt-Shift-O", "NEXTCLONE CTRL"); + addAct(start, "h", "HOP" /*, dir */); + addAct(start, "H", "HOP" /*, dir */); + + addAct(start, "%", "EXCHANGECELLS"); + + addAct(start, "Ctrl-X", "EXCISE"); + + addAct(start, "End", "END" /*, dir */); + + for(int i=0; i<=9; i++) + addAct(start, ""+i, "APPENDINPUT"); + addAct(start, "Backspace", "BACKSPACEINPUT"); + + addAct(start, "g", "GOTO"); + addAct(start, "G", "GOTO CTRL"); + + addAct(start, "Esc", "HOMECLR"); + addAct(start, "Home", "HOME"); + + + addAct(start, "v", "RASTER +"); + addAct(start, "Alt-V", "RASTER -"); + addAct(start, "V", "RASTER C+"); + addAct(start, "Alt-Shift-V", "RASTER C-"); + + addAct(start, "F2", "FFACTORY +"); + addAct(start, "Alt-F2", "FFACTORY -"); + addAct(start, "Shift-F2", "FFACTORY C+"); + addAct(start, "Alt-Shift-F2", "FFACTORY C-"); + + + addAct(start, "F3", "SORTALPH"); + + addAct(start, "x", "DIM X+"); + addAct(start, "Alt-X", "DIM X-"); + addAct(start, "y", "DIM Y+"); + addAct(start, "Alt-Y", "DIM Y-"); + addAct(start, "z", "DIM Z+"); + addAct(start, "Alt-Z", "DIM Z-"); + + + addAct(start, "X", "DIM CX+"); + addAct(start, "Alt-Shift-X", "DIM CX-"); + addAct(start, "Y", "DIM CY+"); + addAct(start, "Alt-Shift-Y", "DIM CY-"); + addAct(start, "Z", "DIM CZ+"); + addAct(start, "Alt-Shift-Z", "DIM CZ-"); + + addAct(start, "~", "SWAPCRSR"); + addAct(start, "<", "FETCH"); + addAct(start, ">", "FETCH CTRL"); + + addAct(start, "Ctrl-<", "ACCURSE CTRL"); + addAct(start, "Ctrl->", "ACCURSE"); + + // addAct(start, "Alt-x", "PSHDIM X+"); + // addAct(start, "Alt-y", "PSHDIM Y+"); + // addAct(start, "Alt-z", "PSHDIM Z+"); + + + + + /* + addAct(start, "L", "MARK X+"); + addAct(start, "J", "MARK X-"); + addAct(start, "I", "MARK Y-"); + addAct(start, "<", "MARK Y+"); + */ + + addAct(start, "Enter", "EXEC"); + + + addAct(start, "m", "MARK"); + + addAct(start, "u", "UNDO"); + addAct(start, "Ctrl-U", "REDO"); + addAct(start, "Ctrl-S", "COMMIT"); + + addAct(start, "Ctrl-F", "FINDTEXT"); + + addAct(start, "MouseClicked1", "MOUSESETC"); + addAct(start, "MouseClicked2", "MOUSEEXEC"); + addAct(start, "MouseClicked3", "MOUSEMARK"); + + addAct(start, "Delete", "DELETESCRAM"); + + addAct(start, "F1", "HELP"); + addAct(start, "q", "QUIT"); + } + + static public void putDefTextBinds(ZZCell start) { + start.setText("Text insert mode"); + ZZCell dir = start; + addAct(dir, "DEFAULT", "TXTINSERT"); + } + static public void putDefCmds(ZZCell fromHome) { + String [][] foo = { + { "EDITHACK" }, + {}, + { "NEWVIEWS" }, + { "TextCloud.TESTWIN" }, +/* doesn't work currently + { "ZZMbox.READMBOX", "ZZMbox.CREATEFLOBWINDOW" }, +*/ + { "NileDemo.UPDATE" }, + { "SplitNileDemo.UPDATE" }, + { "CreateCursors" }, + { "UPDATEWINS" }, + { "EDITVIEW" } , + { "XML.IMPORT" } /* , + { "---- (obsolete?)" }, + { "CNCT X+", "CNCT X-" }, + { "CNCT Y+", "CNCT Y-" }, + { "CNCTI X+", "CNCTI X-" }, + { "CNCTI Y+", "CNCTI Y-" }, + { "CNCTC X+", "CNCTC X-" }, + { "CNCTC Y+", "CNCTC Y-" }, + { "SETDIMS", "SETCDIMS" }, + //{ "RENDER" }, + { "TestClang1.1" }, + { "QUIT" }, */ + }; + ZZCell curv = fromHome; + for(int i=0; i0) curh = curh.N("d.1", 1); + curh.setText(foo[i][j]); + } + } + if(true) { + foo = new String[][]{ + { "Dumper.Create" }, + { "Dumper.Read" }, + { "Dumper.Write" }, + { "Dumper.Dump" }, + { "Dumper.Enter" }, + { "Dumper.ChangeID" }, + { "HOME" }, + }; + curv = fromHome.N("d.1", 1); + // curv.setText("Dumping"); // XXX -- set or don't? + // (what's less confusing?) + for(int i=0; i0) curh = curh.N("d.1", 1); + curh.setText(foo[i][j]); + } + } + } + if(false) { + foo = new String[][]{ + { "SNDS T0-", "SNDS T0+" }, + { "SNDS T1+", "SNDS T1-" }, + { "SNDL T0-", "SNDL T0+" }, // locked to the other one + { "SNDL T1+", "SNDL T1-" }, + { "SNDSPLIT", "SNDJOIN+" }, + { "ZZPlayer.PLAY", "ZZPlayer.PLAYLOOP", + "ZZPlayer.PAUSE", "ZZPlayer.STOP" }, + { "ZZPlayer.CRDEMO" }, + }; + curv = fromHome.N("d.1", 1); + curv.setText("Sound"); + for(int i=0; i0) curh = curh.N("d.1", 1); + curh.setText(foo[i][j]); + } + } + } + } +} diff --git a/Java/ZZPrimitiveCommand.zob b/Java/ZZPrimitiveCommand.zob new file mode 100644 index 0000000..017d117 --- /dev/null +++ b/Java/ZZPrimitiveCommand.zob @@ -0,0 +1,59 @@ +/* +ZZPrimitiveCommand.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; + +/** A ZZCommand interface to ZZPrimitiveActions. + */ + +public class ZZPrimitiveCommand extends ZZCommand implements ZOb { + + STRUCTPARAMS { + ZZCell code + = null; + } + + INITIALIZE { + if(code == null) + throw new ZZError("Must specify ZZPrimitiveCommand code!"); + } + + ZZPrimitiveActions pa = new ZZPrimitiveActions(); + + public void execCallback( + ZZCell target, + ZZView view, + ZZView cview, + String key, + Point pt, + ZZScene xi + ) { + pa.execCallback(code, target, view, cview, key, pt, xi); + } + + public void exec(ZZCell param) { + throw new ZZError("ZZPrimitiveCommand currently does not support " + +"primitives which aren't UI callbacks."); + } +} \ No newline at end of file diff --git a/Java/ZZRODimension.java b/Java/ZZRODimension.java new file mode 100644 index 0000000..938d553 --- /dev/null +++ b/Java/ZZRODimension.java @@ -0,0 +1,45 @@ +/* +ZZRODimension.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A read-only dimension. + * This class simply extends ZZDimension by implementing the + * abstract methods that would modify the dimension by code that + * simply throws an exception. + * The only method that subclasses will need to override is s. + */ + +public abstract class ZZRODimension extends ZZDimension { +public static final String rcsid = "$Id: ZZRODimension.java,v 1.10 2000/11/05 19:11:13 tjl Exp $"; + public abstract ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o); + public void connect(ZZCellHandle c, ZZCellHandle d) { + throw new ZZError("Read-only dimension"); + } + public void disconnect(ZZCellHandle c, int dir) { + throw new ZZError("Read-only dimension"); + } + public void excise(ZZCellHandle c) { + // Do nothing. + } +} diff --git a/Java/ZZScene.java b/Java/ZZScene.java new file mode 100644 index 0000000..f996333 --- /dev/null +++ b/Java/ZZScene.java @@ -0,0 +1,74 @@ +/* +ZZScene.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** An interface for obtaining clicked -objects based on coordinates. + * This is what is given with mouse events. + */ + +public interface ZZScene { +String rcsid = "$Id: ZZScene.java,v 1.4 2000/09/19 10:31:58 ajk Exp $"; + + /** Get an identifying object for the given point on this canvas. + * This is one point where OO decoupling doesn't work properly: + * different things want to return different kinds of information: + * CellThings want to return the cell, TextSpans a VStream.Pos and so on. + */ + Object getObjectAt(int x, int y); + + /** Render this canvas, things interpolated with the given other canvas, + * on the given graphics context. + * Interpolation is used for great advantage to show the user what the + * relationship between two different states is, i.e. which cells + * are the same. The modular nature of the ZZCanvas allows Things + * to define their own interpolation semantics: for example, by default, + * links are not rendered at all when interpolating and cells + * are interpolated linearly. + */ + void renderInterp(Graphics g, ZZScene other, float fract); + + + /** Paint a cursor-like thing using XOR. + * Originally intended for drawing a ghost cursor on text when + * moving the mouse in order to show where a click would put the cursor. + */ + void renderXOR(Graphics g, int x, int y); + + /** Is interpolation to the given canvas visually useful. + * This routine returns true if there is something in this canvas + * which will be seen animated when interpolating to the new canvas. + * For example, when only changing a dimension, some cells stay where + * they are and all the others are replaced by other cells (usually... + * there are of course situations where some cells move on the screen + * when changing a dimension). In this case, the user is better served + * by not animating but simply displaying the new state as fast as + * possible. + */ + boolean isInterpUseful(ZZScene s2); + + /** Render this scene in the given graphics context. + */ + void render(Graphics g); +} diff --git a/Java/ZZSlicedDimSpace.java b/Java/ZZSlicedDimSpace.java new file mode 100644 index 0000000..e7b804a --- /dev/null +++ b/Java/ZZSlicedDimSpace.java @@ -0,0 +1,116 @@ +/* +ZZSlicedDimSpace.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import org.gzigzag.*; +import java.util.*; + +/** A space consisting of primitive slices. + * NOTE: the current code does not support changing slice IDs + * *AT ALL*. + */ + +class EHSEFKUHESMFKMEFKLSEF { } + +/* + +public class ZZSlicedDimSpace extends ZZDimSpace { +public static final String rcsid = "$Id: ZZSlicedDimSpace.java,v 1.10 2000/11/07 23:07:33 tjl Exp $"; + + static final String getOrigID(String c) { + return c.substring(c.indexOf('-')+1); + } + static final int getSliceID(String c) { + return Integer.parseInt(c.substring(0,c.indexOf('-'))); + } + static final String getConvID(int sli, String ores) { + return ""+sli+"-"+ores; + } + + ZZDimSpace[] slices; + + protected DimCell getNewCell(String id) { + int sl = getSliceID(id); + String or = getOrigID(id); + DimCell ocell = slices[sl].getNewCell(or); + id = getConvID(sl, ocell.getID()); + return (DimCell)getCellByID(id); + } + protected DimCell getNewCell() { + throw new ZZError("Can't make new cells from nothing in sliced space"); + } + + public ZZSlicedDimSpace(ZZDimSpace[] s) { + slices = s; + } + protected String getText(String id) { + int sl = getSliceID(id); + String or = getOrigID(id); + ZZCell c = slices[sl].getCellByID(or); + return c.getText(); + } + + protected Span getSpan(String id) { + int sl = getSliceID(id); + String or = getOrigID(id); + ZZCell c = slices[sl].getCellByID(or); + Span s = c.getSpan(); + return s; + } + protected void setText(String id, Object cont) { + int sl = getSliceID(id); + String or = getOrigID(id); + ZZCell c = slices[sl].getCellByID(or); + if(cont instanceof Span) { + c.setSpan((Span)cont); + } else { + c.setText((String)cont); + } + } + + public ZZCell getHomeCell() { + return getCellByID(getConvID(0, slices[0].getHomeCellID())); + } + + public ZZDimension createDimension(String s) { + if(s.equals("d.preflets")) return null; + if(s.equals("d.slices")) return new SlicedHomes(this); + if(s.equals("d.slicesame")) return new SlicedSame(this); + ZZDimension[] dims = new ZZDimension[slices.length]; + for(int i=0; icells and are defined in ZZCell.java. + *

    + * Also included are default operations for space. These can be overridden + * in concrete implementations. Note how we can leave undecided witch + * classes and objects are responsible for some operations, as it's only + * needed that the space contains all specified information. + *

    + * The dimensions are listed in the space itself, on two ranks from + * the Home cell, along d.masterdim which includes all dimensions and + * d.userdim which excludes the system dimensions that are generally + * not used by the user (such as d.cursor, d.cursor-cargo). + * (XXX d.userdim not yet) + *

    + * The event loop mechanism is included in this object since the + * event loop is per-space. Currently, the way to prevent events + * from propagating is to lock this object using synchronized(){}. + * The relationship of this synchronization to remote objects is not + * yet clear, as well as interaction with slices and such + * so this synchronization may change in the future + * to a pair of freeze and thaw method calls. + */ + +public abstract class ZZSpace { +public static final String rcsid = "$Id: ZZSpace.java,v 1.22 2001/02/23 12:20:32 bfallenstein Exp $"; + public static boolean dbg = false; + protected static void p(String s) { if(dbg) ZZLogger.log(s); } + protected static void pa(String s) { ZZLogger.log(s); } + + // CORE FUNCTIONALITY OF ZZSPACE + + /** Obtain the unique ID for this space. + * Note that this method may not throw an exception. + * if the space not have an ID. + */ + public String getIDOrNull() { + return null; + } + + /** Obtain the unique ID for this space. + * Note that this method may throw an exception, + * if the space not have an ID. + */ + public String getID() { + String rv = getIDOrNull(); + if (rv == null) { + throw new NullPointerException("This space has no valid ID"); + } + return rv; + } + + /** Set the unique ID for this space. + * Note that this method may throw an exception + * if the space does not support space IDs. + */ + public void setID(String id) { + throw new ZZError("Setting space ID not supported by this space"); + } + + /** Get the home cell of this space. + * The home cell is where everything begins */ + abstract public ZZCell getHomeCell(); + + /** Get a cell by its ID. + */ + public ZZCell getCellByID(String s) { + throw new ZZError("Not implemented for this space"); + } + + /** Get the appendable string scroll of this space. + */ + public StringScroll getStringScroll() { + return null; + } + /** Get the string scroll with the given identifier. + * (XXX???) + */ + public StringScroll getStringScroll(String name) { + return null; + } + + /** Find all cells whose span overlaps sp. + */ + public ZZCell[] overlaps(Span sp) { + return null; + } + + + // TIMESTAMP AND UNDO. + // THESE NEED NOT DO ANYTHING. + + /** Timestamp the space. + */ + public int stamp() { + return -1; + } + /** Undo to the previous timestamp. + */ + public void undo() { + } + /** Redo to the next timestamp. + */ + public void redo() { + } + /** Commit the changes. + * Commits may define their own timestamps i.e. after commit the + * micro-level timestamps may not be accessible. + */ + public int commit() { + return -1; + } + + + // TRAVERSING + + /** Returns enumeration over the cells in this space - also in slices. + */ + public Enumeration cells() { + return new Enumeration() { + ZZCell next = getHomeCell(); + ZZCell slice = next; // Homecell of current slice + public boolean hasMoreElements() { + if(next == null) + return false; + return true; + } + public Object nextElement() { + if(next == null) + throw new NoSuchElementException(); + ZZCell ret = next; + next = next.s(d.cellcreation, 1); + if(next == null) // End of this slice + slice = next = + slice.s(d.slices, 1); + return ret; + } + }; + } + + /** Get a list of the dimensions in the space. + * This function will likely change in the future as it is possible + * that dimensions become cells instead of strings. + */ + public String[] dims() { + Vector dims = new Vector(); + ZZCell c = getHomeCell().s(d.masterdim, 1); + while(c != null) { + dims.addElement(c.getText()); + c = c.s(d.masterdim, 1); + } + String[] ret = new String[dims.size()]; + for(int i = 0;i + * This is going away once dimensions are cells, not strings. + */ + class Dims { + public final String cellcreation = "d.cellcreation"; + public final String slices = "d.slices"; + public final String masterdim = "d.masterdim"; + public final String clone = "d.clone"; + } + + /** A nice hack to make it possible to use d.* names. Contains all + * dimensions witch have special meaning and are thus referenced + * to in this class. + */ + Dims d = new Dims(); +} diff --git a/Java/ZZSpacePart.java b/Java/ZZSpacePart.java new file mode 100644 index 0000000..ee8e2b5 --- /dev/null +++ b/Java/ZZSpacePart.java @@ -0,0 +1,95 @@ +/* +ZZSpacePart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; + +/** EXPERIMENTAL: A portion of a ZZ space. + * This is a way to have some cells virtual, i.e. existing only + * when called upon, and whose connections to other cells are algorithmic, + * not stored. + *

    + * For example, it is possible to make a huge tree-like calendar + * with thousands of years at nanosecond precision using these ideas: + * the cell's ID in that part stores the data about the moment and + * the dimensions give the movement from that cell to other cells. + *

    + * Currently, cell IDs in part foo look like foo:... where ... is whatever + * string that part wants to use. + * Dimensions are like d.foo:... where ... is the name in the part. + */ + +public abstract class ZZSpacePart { +public static final String rcsid = "$Id: ZZSpacePart.java,v 1.8 2001/03/08 13:37:16 ajk Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + /** The space part id. This is prepended to all the IDs of the cells + * within this part. (DELIM??!!XXX) + */ + public final String id; + + /** The space this part is a part of. + */ + public final ZZDimSpace space; + + public ZZSpacePart(ZZSpace space, String id) { + this.space = (ZZDimSpace)space; + this.id = id; + } + + /** Obtain a special dimension for this part. + * The dimension name has the prefix stripped off. + * This function may return null. + */ + abstract public ZZDimension getDim(String name); + + /** The home cell for this space part. This is useful in case + * it's not connected to anywhere in the space proper. */ + public String homeID() { return null; } + + public String getText(ZZCellHandle c) { return ""; } + public Span getSpan(ZZCellHandle c) { return null; } + public void setContent(ZZCellHandle c, Object o) { + // do nothing + } + + public Object parseID(String id) { + int ind = id.indexOf(':'); + if(ind < 0) throw new SyntaxError("No delimiter in ID"); + return parseIDPart(id.substring(ind+1)); + } + abstract public Object parseIDPart(String idPart); + + public String toString() { return id; } + + public String generateID(Object parsed) { + String rv = id + ":" + generateIDPart(parsed); + return rv; + } + abstract public String generateIDPart(Object parsed); + + public ZZDimSpace.DimCell getCellByID(String s) { return null; } + + public void postCommitHook() {} +} + diff --git a/Java/ZZTextView.java b/Java/ZZTextView.java new file mode 100644 index 0000000..501d2a2 --- /dev/null +++ b/Java/ZZTextView.java @@ -0,0 +1,106 @@ +/* +ZZTextView.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, rewritten to use AWT by Benja Fallenstein + */ +package org.gzigzag; +import java.awt.event.*; +import java.awt.*; + +/** A text view showing the contents of one cell (the cursor). + * This is shown in a window of its own, using the AWT TextArea component, + * to allow copy-and-paste functions as you know them from PUIs. Basically, + * it's a dirty hack, because it's outside the usual GZZ framework. + */ + +public class ZZTextView extends Frame implements ZZView { +public static final String rcsid = "$Id: ZZTextView.java,v 1.16.2.3 2001/08/16 13:50:01 bfallenstein Exp $"; + static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + ZZCell windowCell; + + /** The cell we show (i.e., the cell currently accursed). + * If reraster is called, but the cell and its text haven't changed, we do + * nothing, so that the cursor position will not be screwed. (The text + * is not cached, instead the text in the TextArea component is used: this + * way, if the TextArea itself is used for editing, the text we find there + * will be the new text in the cell, so we will not screw the cursor + * position either.) + *

    + * Note that we simply ignore updates when we have the focus. + */ + ZZCell shown; + + /** Whether we're updating the content of the TextArea right now. + * When we're updating (i.e., write stuff from the structure into + * the text area), we obviously ignore events telling us the content + * of the text area has changed. + */ + boolean isUpdating = false; + + /** Whether the text component currently has the focus. */ + boolean hasFocus; + + public ZZCell getViewcell() { return windowCell; } + public void paintNow(float fract) {} + + TextArea txt = new TextArea("", 100, 100, + TextArea.SCROLLBARS_VERTICAL_ONLY); + + public ZZTextView(ZZCell c) { + windowCell = c; + setLayout(new BorderLayout()); + add(txt, "Center"); + ZZUpdateManager.addView(this); + txt.addTextListener(new TextListener() { + public void textValueChanged(TextEvent e) { + if(isUpdating) return; + shown.setText(txt.getText()); + ZZCursorReal.setOffs(windowCell, txt.getCaretPosition()); + } + }); + txt.addFocusListener(new FocusListener() { + public void focusGained(FocusEvent e) { hasFocus = true; } + public void focusLost(FocusEvent e) { hasFocus = false; } + }); + setBounds(0, 0, 200, 300); + setVisible(true); + reraster(); + } + + public boolean reraster() { + ZZCell accursed = ZZCursorReal.get(windowCell); + if(!hasFocus && (!accursed.equals(shown) || + !accursed.getText().equals(txt.getText()))) { + isUpdating = true; + txt.setText(accursed.getText()); + int offs = ZZCursorReal.getOffs(windowCell); + if(offs == ZZCursorReal.NO_OFFSET) + txt.setCaretPosition(0); + else + txt.setCaretPosition(offs); + shown = accursed; + isUpdating = false; + } + return false; + } +} diff --git a/Java/ZZTraverseCB.java b/Java/ZZTraverseCB.java new file mode 100644 index 0000000..bf5d9f3 --- /dev/null +++ b/Java/ZZTraverseCB.java @@ -0,0 +1,43 @@ +/* +ZZSpace.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +/** An interface for creating a ZZ space through traversal. + * Cells are represented by their IDs. + */ + +public interface ZZTraverseCB { +String rcsid = "$Id: ZZTraverseCB.java,v 1.6 2000/09/19 10:31:58 ajk Exp $"; + + /** Start the traversal from the given home cell ID. + */ + void start(String home); + /** Insert the new cell. + */ + void cell(String cur, String dim, int dir, String which, + String content); + /** Connect the two given cells. */ + void connect(String c1,String dim, int dir, String c2); + /** That's all, folks. */ + void finish(); +} diff --git a/Java/ZZUpdateManager.java b/Java/ZZUpdateManager.java new file mode 100644 index 0000000..7d0cc1c --- /dev/null +++ b/Java/ZZUpdateManager.java @@ -0,0 +1,253 @@ +/* +ZZUpdateManager.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A single global instance to manage the updating of views. + * The views are set in a priority order so that even if the user is + * moving fast, he will get an immediate response through the less important + * views not being updated at each step. + */ + +public class ZZUpdateManager implements Runnable { +public static final String rcsid = "$Id: ZZUpdateManager.java,v 1.29 2001/02/27 08:36:15 raulir Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + /** The order of views, from the most important to the least. + */ + private static Vector ordering = new Vector(); + + /** Whether an update is currently in progress, through + * a view being painted. + */ + private static boolean updating; + private static int disabled; + private static boolean noanimation; + /** Whether the currently ongoing update should stop immediately + * and restart from the beginning + */ + private static boolean restartUpd = false; + + public static void addView(ZZView v) { ordering.addElement(v); } + public static void rmView(ZZView v) { ordering.removeElement(v); } + + /** Set the view that has the privilege of animating the next + * update. + * Setting this to null will make all views update fast. + */ + public static void setFast(ZZView v) { + p("Setfast: "+v + " cur: "+ordering.elementAt(0)); + if(v == null) { + noanimation = true; + return; + } + if(ordering.elementAt(0)!=v) { + ordering.removeElement(v); + ordering.insertElementAt(v, 0); + } + } + + + /* Called by a space to inform that some cells have been + * changed + */ + public static void chg() { + p("UPDMANAGER CHG"); + if(restartUpd) return; + synchronized(ordering) { + restartUpd = true; + ordering.notifyAll(); + } + p("UPDMANAGER CHGOUT"); + } + + /** Disable all updating of views. + * XXX While frozen, might consider updating e.g. once every + * second... + */ + public static void freeze() { + p("ZZUpdatemanager freeze"); + synchronized(ordering) { disabled++; } + p("ZZUpdatemanager frozen "+disabled); + } + /** Enable again the updating of views. */ + public static void thaw() { + p("ZZUpdatemanager thaw"); + synchronized(ordering) { + if(disabled<=0) + throw new ZZError("thaw() without matching freeze()!"); + if(--disabled==0) ordering.notifyAll(); + } + p("ZZUpdatemanager thawed "+disabled); + } + + static ZZUpdateManager m = new ZZUpdateManager(); + static Thread t= new Thread(m); + static { + p("STARTORDTHREAD"); + t.start(); + } + + public void run() { + try { + int ind = -1; + boolean reras = true; + boolean anim = false; + Vector curUpdVec = new Vector(); + + while(true) { + p("STARTORD"); + synchronized(ordering) { + p("STARTORD SYNCHED"); + if(!anim) ind++; + updating = false; + try { + while(disabled>0 || (ind>=curUpdVec.size() && !restartUpd)) { + p("STARTORD "+disabled+" "+ind+" "+restartUpd); + ordering.wait(); + } + } catch(Exception e) { + ZZLogger.exc(e); + } + p("STARTORD WAITED"); + updating = true; + if(restartUpd) { + restartUpd = false; + curUpdVec = (Vector)ordering.clone(); + ind = 0; + reras = true; + // Try to make the system stop less at + // inconvenient, unequal times. + + // System.gc(); // doesn't seem to work. + } + if(curUpdVec.size()==0) continue; + } + try { + p("STARTORD DOING " + ind + " "+ curUpdVec+" "+reras); + ZZView v = (ZZView)curUpdVec.elementAt(ind); + if(ind==0) { // animate if need be + if(reras) { + timeNewCycle(); + + anim = v.reraster(); + reras = false; + } + float fract = timeAnimFract(); + + if(fract >= 1 || !anim || noanimation) { + fract = 1; + anim = false; + noanimation = false; + } + p("PN 0: "+fract+" "+anim+" "+lastStart+" "+millis); + // XXX paintNow() is not really safe here, because ZZ code + // in general isn't thread-safe. If Kaffe someday provides + // EventQueue.invokeAndWait(), this could be fixed. + boolean care = ZZDrawing.instance.enableQuality(false); + v.paintNow((float)fract); + if (fract == 1 && care) { + ZZDrawing.instance.enableQuality(true); + v.paintNow(1.0f); + } + } else { + p("PN: "+ind); + v.reraster(); + // XXX Ditto. + boolean care = ZZDrawing.instance.enableQuality(false); + v.paintNow(1.0f); + if (care) { + ZZDrawing.instance.enableQuality(true); + v.paintNow(1.0f); + } + } + ((java.awt.Component)v).getToolkit().sync(); + } catch(ZZError e) { + ZZLogger.exc(e); + System.out.println("EXCEPTION WHILE UPDATING!"); + } + p("STARTORD DONE: anim "+anim); + } + } finally { + System.out.println("HELP! UPDATE LOOP STOPPED. XXX"); + } + } + + static final long defmillis = 800; + /** The time before the next user event + * to try to be ready. + */ + static final long trybefore = 150; + /** The time to increment the interval with. + */ + static final long inctime = 80; + private static long lastStart = 0; + /** The interval between start and end of animation. + */ + private static long millis = defmillis; + + /** Called when we begin a new animation. */ + private void timeNewCycle() { + long cur = System.currentTimeMillis(); + // Interval between start of last animation and start of the new one. + long sinceLast = cur-lastStart; + + // sinceLast - millis = interval between end of last animation and + // start of the new one. We try to end the last animation + // trybefore ticks before the start of the new one, so if + // sinceLast - millis < trybefore, the animation takes too long. + if(sinceLast - millis < trybefore) + millis = sinceLast-trybefore; // Shorten the animation time. + + // If the animation didn't take too long, and if it's at least a unit + // (inctime) shorter than it was by default, gradually lengthen it. + else if(millis < defmillis - inctime) + millis += inctime; + + lastStart = cur; + } + + private float timeAnimFract() { + long cur = System.currentTimeMillis(); + + double fract = 1.0; + + // If we are animating at all (20 milliseconds is + // minimum time we try to use animation with), + // calculate the fraction of the animation we are at. + if(millis > 20) + fract = (cur-lastStart) / (double)millis; + + // Test for a really weird JVM problem. + if(cur - lastStart >= millis && fract < 1) { + System.out.println("AAAARRRRRGGGHHH!!! Division problem "+ cur + " "+lastStart+" "+millis); + } + + return (float)fract; + } + +} + + diff --git a/Java/ZZUtil.java b/Java/ZZUtil.java new file mode 100644 index 0000000..5c40fca --- /dev/null +++ b/Java/ZZUtil.java @@ -0,0 +1,575 @@ +/* +ZZUtil.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.datatransfer.*; +import java.util.*; + +/** Some general routines that don't fit anywhere else. + */ + +public class ZZUtil { +public static final String rcsid = "$Id: ZZUtil.java,v 1.35.4.3 2002/03/07 19:36:53 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + /** Set a number of strings onto a rank. + * Overwrites existing cells and creates new for the rest. + */ + static public void putStrings(ZZCell start, String dim, boolean incStart, + String[] strs) { + for(int i=0; i= nmin) break; + throw new ZZError("Not enough strings: "+i); + } + } + p("GetStrs: "+start.getID()); + r[i] = start.getText(obs); + } + if(i == nmax) return r; + String[] r2 = new String[i]; + System.arraycopy(r, 0, r2, 0, i); + return r2; + } + static public String[] getStrings(ZZCell start, String dim, + boolean incStart, + int nmin, int nmax) { + return getStrings(start,dim,incStart,nmin,nmax,null); + } + + static public int[] getInts(ZZCell start, String dim, boolean incStart, + int nmin, int nmax,ZZObs obs) { + String[] s = getStrings(start, dim, incStart, nmin, nmax, obs); + int[] r = new int[s.length]; + for(int i=0; i 256) fract = 256; + int p = 256-fract; + int m = fract; + return new Color( + (c1.getRed()*p + c2.getRed()*m) / 256, + (c1.getGreen()*p + c2.getGreen()*m) / 256, + (c1.getBlue()*p + c2.getBlue()*m) / 256); + } + + /** Give a subtly randomly shaded version of the given color. + */ + static public Color perturb(Color c1) { + return new Color( + pff(c1.getRed()), + pff(c1.getGreen()), + pff(c1.getBlue()) + ); + } + + /** Perturb an integer in the range 0..255. + */ + static int pff(int f) { + int offs = (int)(50 * (Math.random() - 0.5)); + f += offs; + if(f < 0) f = 0; + if(f > 255) f = 255; + return f; + } + + /** Find the index of the given string that is closest to + * the given X coordinate using FontMetrics. + */ + static public int findStringHit(String txt, int x, FontMetrics fm, + boolean alwaysmin) { + if(x <= 0) return 0; + int min = 0; int max = txt.length(); + int lmin = 0; int lmax = fm.stringWidth(txt); + while(max-min > 1) { + int cur = (max+min) / 2; + int curlen = fm.stringWidth(txt.substring(0, cur)); + p("Iter: "+cur+" "+curlen+" "+max+" "+lmax+" "+min+" "+lmin); + if(curlen > x) { + max = cur; + lmax = curlen; + } else { + min = cur; + lmin = curlen; + } + // XXX potential for infinite loop for weird fontmetrics? + } + // now we should have it... + int mx = lmax - x; + int mn = x - lmin; + if(mn < mx || alwaysmin) + return min; + else + return max; + } + + static public int findStringHit(String txt, int x, FontMetrics fm) { + return findStringHit(txt, x, fm, false); + } + + /** Append a command-type thing. Strings are put in cells, cells are + * cloned. + */ + static public ZZCell appendCommand(ZZCell cur, + String cdim, String pdim, Object[] objs) { + ZZCell tmp = null; + if(objs[0] instanceof String) + (cur = cur.N(cdim, 1)).setText((String)objs[0]); + else { + tmp = ((ZZCell)objs[0]).N("d.clone", 1); + cur.connect(cdim, 1, tmp); + cur = tmp; + } + ZZCell prev = cur; + for(int i=1; i + * If a dimension is given, then contents of this rank are concatenated. + */ + static public void puiCopy(ZZCell from, String dim) + { + StringBuffer cont = new StringBuffer(from.getText()); + if(dim != null) { + ZZCell cur = from.s(dim, 1); + while(cur != null) { // XXX Use LoopDetector + String s = cur.getText(); + if(s.equals("")) + cont.append('\n'); + else + cont.append(' ').append(s); + cur = cur.s(dim, 1); + } + } + puiCopy(cont.toString()); + } + + static public void puiCopyRank(ZZCell from, String dim) + { + StringBuffer cont = new StringBuffer(from.getText()+"\n\n"); + if(dim != null) { + ZZCell cur = from.s(dim, 1); + while(cur != null) { // XXX Use LoopDetector + cont.append(cur.getText() + "\n\n"); + cur = cur.s(dim, 1); + } + } + puiCopy(cont.toString()); + } + + static public void puiCopy(ZZCell from) { + puiCopy(from.getText()); + } + + static public String puiGetClipText() + { + Clipboard clipboard = getPUIClipboard(); + Transferable content = clipboard.getContents(new Object()); + String s = ""; + if(content != null) { + try { + s = (String) content.getTransferData(DataFlavor.stringFlavor); + } catch (Exception e) { + ZZLogger.exc(e); + return null; + } + } + return s; + } + + /** Paste from PUI clipboard. + * Change a cell's contents to the (text) contents in the clipboard + * of the surrounding PUI. Return true if action succeeded; return + * false if not (because the clipboard didn't contain text). + *

    + * XXX does nothing if cell is span (but what *should* be done?) + */ + static public boolean puiPaste(ZZCell to) { + if(to.getSpan() != null) return false; + p("PuiPASTE"); + String s = puiGetClipText(); + if(s == null) return false; + to.setText(s); + return true; + } + + /** An interface which establishes an ordering (partial or full, + * depending on context) between cells. + */ + public interface Comparator { + /** Compare the things represented by the two cells to each other. + * @return 0 if equal, 1 if c1 greater, -1 if c2 greater. + */ + int compare(ZZCell c1, ZZCell c2); + } + + /* after sorting */ + static private void sameToClone(ZZCell c1, String dim, int dir, ZZCell c2, + Comparator comp){ + //pa("CLONING\n"); + ZZCell cur = c1; + for ( cur = c1.s(dim,dir); cur != null;){ + if ( c1 == c2 ) break; + ZZCell next = cur.s(dim, dir); + + if ( comp.compare(c1,cur) == 0 ){ + c1.insert( "d.clone", 1, cur ); + cur.excise(dim); + //pa("CLONED\n"); + } else { + c1 = cur; + } + cur = next; + + } + } + + static private int partition(ZZCell[] v, int l, int r, Comparator s){ + int i = l-1; + int j = r; + int len = v.length; + ZZCell p = v[r]; + //if ( p == null ) return 0; + ZZCell tmp; + while( true ){ + while(s.compare(v[++i], p) < 0 ){ + if ( i >= len ) break; + } + while(s.compare(p, v[--j]) < 0 ){ + if ( j <=0 ) break; + } + if ( i >= j ) break; + + tmp = v[i]; + v[i] = v[j]; + v[j] = tmp; + } + + tmp = v[i]; + v[i] = v[r]; + v[r] = tmp; + + return i; + } + + + static private void qs(ZZCell[] table, int l, int r,Comparator comp){ + if ( l < r ) { + int i = partition(table,l,r,comp); + if ( i == r ) { i--; } + qs(table,l,i,comp); + qs(table,i+1,r,comp); + } + } + + // yet another sorting algorithm + // this isn't too good, feel free to make a better one + static private void qsRange(ZZCell c1, String dim, int dir, ZZCell c2, + Comparator comp) { + if(c1 == c2) return; + + if ( c1 == null || c2 == null ) return; + // calculate the size of the table + + ZZCell first = c1; + int len = 1, i = 0; + for( ; c1 != c2; len++){ + c1 = c1.s(dim,dir); + if ( c1 == null ) return; + } + if ( len < 1 ) return; + + // read to table + ZZCell[] table = new ZZCell[len]; + c1 = first; + for( i = 0; i < len; i++){ + table[i] = c1; + c1 = c1.s(dim,dir); + } + + qs( table,0,len-1, comp ); + + c1 = first; + + if( c1 != table[0]) + c1.insert(dim, -dir, table[0]); + + for(i = 1 ; i < len; i++){ + c1.insert(dim, dir, table[i]); + c1 = table[i]; + } + } + + static private void sortRange(ZZCell c1, String dim, int dir, ZZCell c2, + Comparator comp) { + + // p("SortRange: "+c1.getText()+" "+c2.getText()); + if(c1 == c2) return; + + ZZCell first = c1; + ZZCell last = c2; + ZZCell cur; + for(cur = c1.s(dim, dir); cur != null;) { + // p("cur: "+cur.getText()); + ZZCell next = cur.s(dim, dir); + int cp = comp.compare(c1, cur); + if(cp > 0) { + // p("move"); + if(cur == c2) last = c2.s(dim, -dir); + c1.insert(dim, -dir, cur); + if(first == c1) first = cur; + } + + if(cur == c2) break; + cur = next; + } + if(first != c1) + sortRange(first, dim, dir, c1.s(dim, -dir), comp); + if(c1 != last) + sortRange(c1.s(dim, dir), dim, dir, last, comp); + + } + + /** Sort a rank with a given comparator. + */ + static public void sortRank(ZZCell c, String dim, int dir, + Comparator comp, boolean includeThis) { + sortRank( c, dim, dir, comp, includeThis, false); + } + + static public void sortRank(ZZCell c, String dim, int dir, + Comparator comp, + boolean includeThis, boolean clone) { + ZZCell c1; + if(!includeThis) + c1 = c.s(dim, dir); + else c1 = c; + if(c==null) return; + + //long t0 = System.currentTimeMillis(); + //sortRange(c1, dim, dir, c.h(dim, dir), comp); + qsRange(c1, dim, dir, c.h(dim, dir), comp); + //pa("TIME USED SORTING = " + (System.currentTimeMillis() - t0) ); + + if(!includeThis) + c1 = c.s(dim, dir); + else c1 = c; + + if ( clone ) + sameToClone(c1, dim, dir, c.h(dim, dir), comp); + } + + + /** Show the dimension cross of a flob view. + */ + static public void showFlobDims(FlobSet into, + FlobFactory fact, ZZCell view, int n) { + + Dimension s = fact.getSize(null, 1); + ZZCell dim = view.s("d.dims", 1); + ZZCell[] cdims = new ZZCell[3]; + int i=0; + for(; dim != null && i < n; i ++) { + cdims[i] = ZZCursorReal.get(dim); + if(cdims[i] == null) + throw new ZZError("No dimension"); + dim = dim.s("d.dims", 1); + } + Flob fl = fact.makeFlob(into, cdims[0], cdims[0], 1, + s.width, 0, 1, s.width, s.height); + fl.flobPath = "dim"; + fl = fact.makeFlob(into, cdims[1], cdims[1], 1, + 0, s.height, 1, s.width, s.height); + fl.flobPath = "dim"; + if(n > 2) { + fl = fact.makeFlob(into, cdims[2], cdims[2], 1, + s.width, s.height, 1, s.width, s.height); + fl.flobPath = "dim"; + } + int wh = s.width / 2; + int hh = s.height / 2; + into.add(new LineDecor( + new int[] { + wh, hh, wh, s.height, + wh, hh, s.width, s.height, + wh, hh, s.width, hh + }, + 12, + Color.red, + 1 + )); + + } + + + /** Create a natural-looking spline between two vectors. + * Returns an array of alternating x and y coordinates of + * a polyline. + * XXX Contains many constants that are just fixed. + * XXX Needs to be prettified a bit. + */ + static public int[] bulgeCurve( + int x0, int y0, int dx0, int dy0, + int x1, int y1, int dx1, int dy1, int NPTS) { + // Formula: x = t*(x0 + c*t*v_0) + (1-t) * (x1 + c*(1-t)*v_1) + p("bulge: "+x0+" "+y0+" "+dx0+" "+dy0+" "+x1+" "+y1+" "+ + dx1+" "+dy1+" "); + int dx = (dx0 - dx1) / 2; + int dy = (dy0 - dy1) / 2; + int dotp = dx * (x1-x0) + dy * (y1-y0); + int det = dx * (y1-y0) - dy * (x1-x0); + // if(dotp < 0 && + int[] res = new int[NPTS*2]; + // Polynomial for factor. + // a*x + b*x^3 is the polynomial through (-1,-1), (0,0) and (1,1) + // whose derivative at -1 and 1 is zero. + // Thus, it is suitable for curving. + float a = (float)1.5; + float b = (float)-0.5; + float tense = (float)20.0/NPTS; + for(int i=0; i + * In event routines, passed instead of cells for update purposes + * (asking ZZUpdateManager to make this view the fast-updated one). + * Once ZZWindows are finished, should be replaced with ZZCell of + * a ZZWindow. + *

    + * Expect a parameter "complexity" to be added to reraster and paintNow + * in the future in order for the ZZUpdateManager to be able to control + * the frame rate. + */ +public interface ZZView { +String rcsid = "$Id: ZZView.java,v 1.18 2000/09/19 10:31:58 ajk Exp $"; + /** Called to enquire whether this view needs an update, given + * that certain cells have been changed. + * NOT YET USED + */ + // public boolean needUpdate(ZZCell[] changed); + // XXX dimensions of chgd cells! + + /** Recreate the view in memory (raster the cells etc). + * @return true if it would be useful for the view to animate + * to the next view. + */ + boolean reraster(); + /** Called to tell that this view should paint itself right now. + * @param fraction The fraction between the old and the new views + * the animation should be at. + */ + void paintNow(float fraction); + + /** Get the cell in the structure representing this view. + */ + ZZCell getViewcell(); +} diff --git a/Java/ZZViewComponent.java b/Java/ZZViewComponent.java new file mode 100644 index 0000000..42708ae --- /dev/null +++ b/Java/ZZViewComponent.java @@ -0,0 +1,287 @@ +/* +ZZViewComponent.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.event.*; +import java.awt.*; +import java.util.*; + +/** A generic view as an AWT component. + */ +abstract public class ZZViewComponent extends Panel implements ZZView, + MouseListener, MouseMotionListener { +public static final String rcsid = "$Id: ZZViewComponent.java,v 1.48.2.4 2002/02/10 12:39:20 bfallenstein Exp $"; + static public boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + ZZCell viewCell;public ZZCell getViewcell() { return viewCell; } + ZZKeyBindings kb; + ZZView ctrlView, dataView; + + boolean needreraster = false; + boolean validraster = false; + + ZZViewComponent parentView; + + Component pushedViewPanel; + ZZViewComponent pushedView; + + /** ZZViewComponent per viewCell. + */ + static Hashtable cpts = new Hashtable(); + + static void redoCtrls(ZZCell vc) { + if(vc == null) throw new ZZError("vc == null"); + + if(vc.getRankLength("d.ctrlview") > 2) + throw new ZZError("d.ctrlview rank with more than two cells!"); + + ZZCell cc, dc; + if((cc = vc.s("d.ctrlview", -1)) != null) + dc = vc; + else if((dc = vc.s("d.ctrlview", 1)) != null) + cc = vc; + else + cc = (dc = vc); + + ZZViewComponent cv = (ZZViewComponent) cpts.get(cc); + ZZViewComponent dv = (ZZViewComponent) cpts.get(dc); + + if(cv == null || dv == null) + // other ZZViewComponent doesn't exist yet + cv = (dv = (ZZViewComponent) cpts.get(vc)); + + cv.setViewPair(dv, true); + dv.setViewPair(cv, false); + +/* // does somebody want it like this? --> + ZZCell h = vc.h("d.ctrlview", -1); + ZZViewComponent c = (ZZViewComponent)cpts.get(h); + if(c != null) { + while((h=h.s("d.ctrlview", 1)) != null) { + ZZViewComponent c1 = (ZZViewComponent)cpts.get(h); + if(c1 != null) + c1.setCtrl(c); + } + } +*/ + } + + public void setViewcell(ZZCell vc0) { + viewCell = vc0; + kb = new ZZKeyBindings1(); + cpts.put(vc0, this); + redoCtrls(viewCell); + } + public void setViewPair(ZZView other, boolean ctrl) { + if(ctrl) { + ctrlView = this; + dataView = other; + } else { + ctrlView = other; + dataView = this; + } + } + + ZZViewComponent(ZZCell viewCell0) { + this(); + setViewcell(viewCell0); + } + + ZZViewComponent() { + addFocusListener(new FocusListener() { + public void focusGained(FocusEvent e) { + p(this + " focusgained"); + repaint(); + } + public void focusLost(FocusEvent e) { + p(this + " focuslost"); + repaint(); + } + }); + + addMouseListener(this); + addMouseMotionListener(this); + + addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + re_raster_soon(); + } + }); + + enableEvents(AWTEvent.KEY_EVENT_MASK); + } + + public void addNotify() { + ZZUpdateManager.addView(this); + super.addNotify(); + } + + public void removeNotify() { + ZZUpdateManager.rmView(this); + super.removeNotify(); + } + + protected void processEvent(AWTEvent e) { + p("ProcessEvent: "+e); + super.processEvent(e); + } + + protected void processKeyEvent(KeyEvent e) { + p("ProcessKeyEvent: "+e); + + // Apply any necessary key event hacks to this event. + e = ZZKeyHacks.keyEventHack(e); + p("After KeyEventHack: "+e); + + int id = e.getID(); + + if(id == e.KEY_PRESSED) { + int kc = e.getKeyCode(); + // These sometimes caused unshifted characters to + // appear. Very odd. + if(kc == e.VK_SHIFT || kc == e.VK_CONTROL || kc == e.VK_ALT + || kc == e.VK_META) { + super.processKeyEvent(e); + return; + } + ZZUpdateManager.freeze(); + try { + //e.consume(); + if(kbd != null) + kb.perform(e, kbd.dataView, kbd.ctrlView, null); + else + kb.perform(e, dataView, ctrlView, null); + ZZObsTrigger.runObsQueue(); + } finally { ZZUpdateManager.thaw(); } + } + // We don't let it go upstairs... + // super.processKeyEvent(e); + } + + + public void mouseEntered(MouseEvent e) { + // XXX ??? + requestFocus(); + } + public void mouseExited(MouseEvent e) { + } + public void mousePressed(MouseEvent e) { + } + public void mouseReleased(MouseEvent e) { + } + public void mouseClicked(MouseEvent e) { + // System.out.println("MOUENT"); + // System.out.println(e); + // kb.perform(k, ZZView.this); + requestFocus(); + // System.out.println("MOURET"); + e.consume(); + } + + public void mouseDragged(MouseEvent e) { + } + public void mouseMoved(MouseEvent e) { + // XXX ??? + requestFocus(); + } + + public void destroy() { + ZZUpdateManager.rmView(this); + } + + ZZViewComponent kbd; + public void setKbdStandin(ZZViewComponent v) { + kbd = v; + } + public void re_raster_soon() { + // p(this + " RERASTERSOON"); + needreraster = true; + repaint(50); + } + + boolean wasInPaint; + float fract; + + boolean dblbuf = true; + private Image cache; + private Dimension cacheSize; + + /** Paint this component into the given graphics object, + * without consideration for double buffering. + */ + public abstract void paintInto(Graphics gr); + + // Paint into the buffer and then into gr. + public void paint(Graphics gr) { + if(dblbuf) { + // XXX Really necessary every time? + Dimension d = getSize(); + if(cache == null || + cacheSize == null || + !cacheSize.equals(d)) { + cacheSize = d; + p("Creating cache: "+d.width+" "+d.height); + cache=null; + if(d.width>0&&d.height>0) + cache = createImage(d.width, d.height); + } + if(cache == null) { + paintInto(gr); + } else { + try { + Graphics g = cache.getGraphics(); + paintInto(g); + // g.dispose() ??? + gr.drawImage(cache, 0, 0, null); + // Dispose this as well? + } catch(Throwable t) { + // FIXME ARGH! + cache = null; + paintInto(gr); + } + } + } else { + // Single-buffer. Flashes. + paintInto(gr); + } + } + public void update(Graphics gr) { paint(gr); } + + public void paintNow(float fract) { + wasInPaint = false; + this.fract = fract; + // p("Paintnow "+this+" "+parentView+" "+reraster+" "+anim); + + Graphics gr = getGraphics(); + if (gr == null) { + repaint(30); + return; + } + paint(gr); + } + +} + + + diff --git a/Java/ZZWindows.java b/Java/ZZWindows.java new file mode 100644 index 0000000..443b804 --- /dev/null +++ b/Java/ZZWindows.java @@ -0,0 +1,231 @@ +/* +ZZWindows.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, killing by Antti-Juhani Kaijanaho, + * triggering and rootwin support by Rauli Ruohonen + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +public class ZZWindows { +public static final String rcsid = "$Id: ZZWindows.java,v 1.23 2001/01/03 16:47:50 raulir Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + /** Iff null, creates Frames at top level. */ + private static Container rootwin; + private static ZZSpace rspace; + private static Hashtable views, frames, ex; + private static ZZObs obs = new ZZObs() { public void chg() { update(); }}; + + /** Must be called before anything else. */ + public static void init(ZZSpace s,Container rootWin) { + rootwin=rootWin; + rspace=s; + if(views!=null) updateEnd(); + views=new Hashtable(); + frames=new Hashtable(); + ex=new Hashtable(); + ZZObsTrigger.chg(obs); + } + public static synchronized void update() { + p("update() start"); + ZZCell rcell=startCell(); + if(rcell==null) throw new ZZError("No 'Windows' cell found!"); + ZZCell s=rcell.getOrNewCell("d.1",1,obs); + if(rootwin!=null) updateRoot(s); + else updateFrames(s); + updateEnd(); + p("update() end"); + } + + // XXX Should create a ZZWindow class for operating on the structure? + public static Rectangle getBounds(ZZCell c, ZZObs obs) { + try { + int[] a=ZZUtil.getInts(c.s("d.1",-1),"d.bounds",false,4,4,obs); + return new Rectangle(a[0], a[1], a[2], a[3]); + } catch(ZZError e) { + return null; + } + } + public static Rectangle getBounds(ZZCell c) { return getBounds(c,null); } + public static void setBounds(ZZCell c, Rectangle r) { + Rectangle b=getBounds(c); + if(b!=null&&b.equals(r)) return; + ZZUtil.putInts(c.s("d.1",-1), "d.bounds", false, + new int[] { r.x, r.y, r.width, r.height }); + } + public static ZZCell startCell() { + return ZZDefaultSpace.findOnClientlist(rspace, "Windows", false); + } + public static synchronized ZZViewComponent getContent(ZZCell c) { + String txt = c.getText(obs); + if(txt.equals("Canvas")) { + ZZCanvasView v; + if(views.get(c) instanceof ZZCanvasView) + v = (ZZCanvasView) views.get(c); + else + views.put(c, v = new ZZCanvasView()); + ZZCell vcell = c.s("d.1", 1,obs); + if(vcell == null) return null; + v.setViewcell(vcell); + return v; + } + return null; + } + + private static void updateRoot(ZZCell s) { + ScalableFont.fmComp=rootwin; + updateWindowAttributes(s,rootwin); + updatePanels(s.s("d.2",1,obs),rootwin); + rootwin.validate(); + } + private static void updateFrames(ZZCell s) { + s=s.s("d.2",1,obs); + while(s!=null) { + boolean created=false; + ZZCell c=s.s("d.1",1,obs); + if(c!=null) { + Frame f=(Frame)frames.get(c); + if(f==null) { + created=true; + frames.put(c,f=new Frame()); + initWindow(c,f); + final ZZCell cell=c; + f.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + p("windowClosing()"); + ZZUpdateManager.freeze(); + try { + cell.s("d.1",-1).excise("d.2"); + ZZObsTrigger.runObsQueue(); + } finally { ZZUpdateManager.thaw(); } + } + }); + } + ScalableFont.fmComp=f; + ex.put(c,c); + Rectangle r=getBounds(c,obs); + if(r!=null&&!f.getBounds().equals(r)) f.setBounds(r); + f.setTitle(s.getText(obs)); + p("Frame name: "+f.getTitle()); + Container cont=getContent(c); + if(cont!=null) { + updateWindowAttributes(s,cont); + cont.removeAll(); // FIXME + updatePanels(c.s("d.2",1,obs),cont); + if(f.getComponentCount()!=1||f.getComponent(0)!=cont) { + p("Changing frame component and validating."); + f.removeAll(); + f.add(cont); + f.validate(); + } + } + if(created) f.setVisible(true); + } + s=s.s("d.2",1,obs); + } + } + private static void updatePanels(ZZCell s,Container parent) { + if(s==null) return; + // FIXME This kludge is here so that applets still work. The real + // functionality should be here Real Soon Now(TM). (Yeah, *right*) + parent.removeAll(); + Container cont=getContent(s.s("d.1",1,obs)); + updateWindowAttributes(s,cont); + parent.add(cont); + } + private static void initWindow(final ZZCell c,final Container w) { + w.addComponentListener(new ComponentAdapter() { + public void componentMoved(ComponentEvent e) { + ZZUpdateManager.freeze(); + try { + ZZObsTrigger.setEnabled(obs,false); + setBounds(c, w.getBounds()); + ZZObsTrigger.setEnabled(obs,true); + ZZObsTrigger.runObsQueue(); + } finally { ZZUpdateManager.thaw(); } + } + public void componentResized(ComponentEvent e) { + ZZUpdateManager.freeze(); + try { + ZZObsTrigger.setEnabled(obs,false); + setBounds(c, w.getBounds()); + ZZObsTrigger.setEnabled(obs,true); + ZZObsTrigger.runObsQueue(); + } finally { ZZUpdateManager.thaw(); } + } + }); + } + private static void updateWindowAttributes(ZZCell c,Container w) { + ZZCell col=c.s("d.color",1,obs); + if(col!=null) { + String colText = col.getText(obs); + + // See if it looks like an URL or a number. + if(Character.isDigit(colText.charAt(0)) || + colText.charAt(0) == '-') + w.setBackground( Color.decode(colText) ); + else { + ZZLogger.log("Not digit first! '"+colText+"'"); + // XXX Find image, store it in the right place (should be + // in content... + /* + URL url = null; + try { + url = new URL(cursor.h("d.photo", 1).getText()); + } catch(MalformedURLException e) { + String s= e.toString(); + g.drawString(s, 0, 0); + return; + } + if(!url.equals(cur)) { + cur = url; + img = getToolkit().getImage(url); + } + if(!g.drawImage(img, 0, 0, null)) { + repaint(1000); + } + */ + } + + if((col=col.s("d.color", 1,obs)) != null) + w.setForeground( Color.decode(col.getText(obs)) ); + } + } + private static void updateEnd() { + for (Enumeration e = views.keys(); e.hasMoreElements();) { + ZZCell cell = (ZZCell) e.nextElement(); + if(!ex.containsKey(cell)) views.remove(cell); + } + for (Enumeration e = frames.keys(); e.hasMoreElements();) { + ZZCell cell = (ZZCell) e.nextElement(); + if(ex.containsKey(cell)) continue; + Frame f = (Frame)frames.get(cell); + f.dispose(); + frames.remove(cell); + } + ex=new Hashtable(); + } +} diff --git a/Java/arch/java2d/ZZDrawingJ2D.java b/Java/arch/java2d/ZZDrawingJ2D.java new file mode 100644 index 0000000..eb27b2d --- /dev/null +++ b/Java/arch/java2d/ZZDrawingJ2D.java @@ -0,0 +1,167 @@ +/* +ZZDrawingJ2D.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.awt.geom.*; + +/** An implementation of ZZDrawing for the Java2D API. + * This allows us to use Java2D's features if present, but + * not to depend on them. + */ + +public class ZZDrawingJ2D extends ZZDrawing { +public static final String rcsid = "$Id: ZZDrawingJ2D.java,v 1.21 2001/03/26 12:41:00 tjl Exp $"; + + public String getType() { + return "Java2D: antialias, alpha(if used), rotation"; + } + + public void setAlpha(Graphics g0, float alpha) { + Graphics2D g = (Graphics2D)g0; + g.setComposite(AlphaComposite.getInstance( + AlphaComposite.SRC_OVER, alpha)); + } + + public RenderingHints qualityHints = new RenderingHints(null); + { + qualityHints.put( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + qualityHints.put( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + qualityHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + qualityHints.put(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_PURE); + + // qualityHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + // RenderingHints.VALUE_FRACTIONALMETRICS_ON); + + } + public RenderingHints speedHints = new RenderingHints(null); + { + speedHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_SPEED); + } + + public void setFIXME(boolean t) { + if (t) { + qualityHints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + qualityHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + qualityHints.put(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_PURE); + } + else { + qualityHints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + qualityHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_SPEED); + qualityHints.put(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_DEFAULT); + } + } + + public boolean enableQuality(boolean t) { + super.enableQuality(t); + return true; + } + + public void setQuality(Graphics g0) { + Graphics2D g = (Graphics2D)g0; + if (qualityEnabled()) g.setRenderingHints(qualityHints); + else g.setRenderingHints(speedHints); + } + + public void setDefaults(Graphics g0) { + //Graphics2D g = (Graphics2D)g0; + //g.rotate(0.1); + } + + /** A flob which shows the given ZZScene rotated by given angle. + */ + public class RotatedSceneFlob extends SceneFlob { + + double rot; + + public RotatedSceneFlob(int x, int y, int d, int w, int h, ZZCell c, FlobSet sc, + double rot) { + super(x,y,d,w,h,c, sc); + this.rot = rot; + } + + + public void transform(double[] srcPtr, double[]dstPts, boolean toExt) { + AffineTransform tr = + AffineTransform.getRotateInstance(rot, x+w/2, y+h/2); + try { + if(toExt) + tr.transform(srcPtr, 0, dstPts, 0, srcPtr.length); + else + tr.inverseTransform(srcPtr, 0, dstPts, 0, srcPtr.length); + } catch(Exception e) { + ZZLogger.exc(e); + } + } + + public Point transform(Point src, Point dst, boolean toExt) { + AffineTransform tr = + AffineTransform.getRotateInstance(rot, x+w/2, y+h/2); + try { + if(toExt) + tr.transform(src, dst); + else + tr.inverseTransform(src, dst); + } catch(Exception e) { + ZZLogger.exc(e); + } + return dst; + } + + void prepareGraphics(Graphics g0, float fract) { + Graphics2D g = (Graphics2D)g0; + if(fract == 0) { + if(rot != 0) + g.rotate(rot, x+w/2, y+h/2); + return; + } + if(!(interpTo instanceof RotatedSceneFlob)) return; // XXX? + double nrot = rot + fract*(((RotatedSceneFlob)interpTo).rot - rot); + if(nrot == 0) return; + g.rotate(nrot, + (int)((x+w/2)*(1-fract) + + fract * (interpTo.x + interpTo.w/2)), + (int)((y+h/2)*(1-fract) + + fract * (interpTo.y + interpTo.h/2)) + ); + } + + + } +} + + diff --git a/Java/arch/javadoc/ZobDoc.java b/Java/arch/javadoc/ZobDoc.java new file mode 100644 index 0000000..6907875 --- /dev/null +++ b/Java/arch/javadoc/ZobDoc.java @@ -0,0 +1,154 @@ +/* +ZobDoc.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; +import com.sun.javadoc.*; + +/** A javadoc doclet for extracting ZOb documentation. + * Note that compiling and running this file requires the tools.jar file + * from JDK 1.3. + */ + +public class ZobDoc extends Doclet { +public static final String rcsid = "$Id: ZobDoc.java,v 1.2 2000/11/05 18:22:54 tjl Exp $"; + + static String[][] lists = new String[][] { + { "org.gzigzag.FlobRaster", "Views", "views.html" }, + { "org.gzigzag.RasterFlobFactory", "CellViews", "cellviews.html" } + }; + + PrintWriter[] listpws = new PrintWriter[lists.length]; + + String outdir = null; + + public static boolean start(RootDoc root) { + ZobDoc zd = new ZobDoc(); + return zd.go(root); + } + + public boolean go(RootDoc root) { + try { + readOptions(root.options()); + + for(int i=0; i"+zobname+""); + pw.println("

    Description

    "); + pw.println(cl.commentText()); +// System.out.println(cl.commentText()); + + pw.println("

    Structural parameters

    "); + FieldDoc[] fields = cl.fields(); + for(int i=0; i"+f.name()+""); + pw.println(f.commentText()); + } +} + diff --git a/Java/arch/syslog/arch.mk b/Java/arch/syslog/arch.mk new file mode 100644 index 0000000..8004ec4 --- /dev/null +++ b/Java/arch/syslog/arch.mk @@ -0,0 +1,19 @@ + + +JNI_INCLUDE = /usr/include/kaffe/ + +all : arch/syslog/libgzigzag-syslog.so + +%.o : %.c + $(CC) $(CFLAGS) -I $(JNI_INCLUDE) -fPIC -c -o $@ $< + +arch/syslog/org_gzigzag_SysLogger.o : arch/syslog/org_gzigzag_SysLogger.c arch/syslog/org_gzigzag_SysLogger.h + +arch/syslog/org_gzigzag_SysLogger.h : org/gzigzag/SysLogger.class + javah -jni -d arch/syslog org.gzigzag.SysLogger + +arch/syslog/libgzigzag-syslog.so : arch/syslog/org_gzigzag_SysLogger.o + $(CC) -shared -o $@ $^ + +clean : + rm -f arch/syslog/libgzigzag-syslog.so arch/syslog/org_gzigzag_SysLogger.o arch/syslog/org_gzigzag_SysLogger.h diff --git a/Java/arch/syslog/org_gzigzag_SysLogger.c b/Java/arch/syslog/org_gzigzag_SysLogger.c new file mode 100644 index 0000000..4ba9ce2 --- /dev/null +++ b/Java/arch/syslog/org_gzigzag_SysLogger.c @@ -0,0 +1,46 @@ +/* +org_gzigzag_SysLogger.c + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +#include "org_gzigzag_SysLogger.h" +#include + +/* + * Class: org_gzigzag_SysLogger + * Method: openlog + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_gzigzag_SysLogger_openlog(JNIEnv * env, jclass class) { + openlog("gzigzag", LOG_CONS, LOG_DAEMON); +} + +/* + * Class: org_gzigzag_SysLogger + * Method: syslog + * Signature: (Ljava/lang/String;Z)V + */ +JNIEXPORT void JNICALL Java_org_gzigzag_SysLogger_syslog(JNIEnv * env, jclass class, jstring msg, jboolean verb) { + const char * s; + + jboolean isCopy = JNI_FALSE; + s = (*env)->GetStringUTFChars(env, msg, &isCopy); + syslog((verb == JNI_TRUE) ? LOG_NOTICE : LOG_INFO, s); + (*env)->ReleaseStringUTFChars(env, msg, s); +} diff --git a/Java/check.pl b/Java/check.pl new file mode 100644 index 0000000..a91eee5 --- /dev/null +++ b/Java/check.pl @@ -0,0 +1,26 @@ +# +# $Id: check.pl,v 1.2 2000/03/13 00:19:29 tjl Exp $ +# +# A small script to check some gzigzag coding rules. + +# Ouch -- fool RCS +$idstr = 'Id:.*'; + +for(@ARGV) { + /\.java/ or die "Sorry, only .java files"; + print "$_:\n"; + open F, "$_"; + my ($clsrcs, $ifrcs, $long, $length); + while() { + /^public static final String rcsid = "\$$idstr\$";/ + and $clsrcs = 1 and next; + /^String rcsid = "\$$idstr\$";/ + and $ifrcs = 1 and next; + s/\t/ /g; + chomp; + $length = length if length > $length; + } + print "\tNo RCS id\n" unless $clsrcs or $ifrcs; + print "\tOverlong line (longest $length)\n" if $length > 80; + +} diff --git a/Java/clang/Data.java b/Java/clang/Data.java new file mode 100644 index 0000000..dd173e9 --- /dev/null +++ b/Java/clang/Data.java @@ -0,0 +1,130 @@ +/* +Data.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag; + +/** An immutable list of Clang data pieces. + * Each piece can be a cell, a string, an int, or a bool. Pieces are + * automatically converted if possible. That way, data can be stored + * virtually someplace, or in cells; from a list of cells, a Data object + * can be constructed which behaves just as a list of objects containing + * the data directly. E.g.: + * Data d = new Data("hi", new Integer(17), new Boolean(false)); + * can be stored as + * new Data(cell1, cell2, cell3); + * if these cells contain the strings "hi", "17", and "false". Saving + * a Data object into a strip of cells is simple: just do something like this: + * + * for(int i=0; i + * (s(i) is the method to get the ith element of a Data strip as a String.) + */ + +public final class Data { +String rcsid = "$Id: Data.java,v 1.3 2001/01/07 18:21:42 bfallenstein Exp $"; + + private Object[] obs; + + public Data() { obs = new Object[0]; } + public Data(Object o1) { obs = new Object[]{o1}; } + public Data(Object o1, Object o2) { + obs = new Object[]{o1,o2}; } + public Data(Object o1, Object o2, Object o3) { + obs = new Object[]{o1,o2,o3}; } + public Data(Object o1, Object o2, Object o3, Object o4) { + obs = new Object[]{o1,o2,o3,o4}; } + public Data(Object o1, Object o2, Object o3, Object o4, Object o5) { + obs = new Object[]{o1,o2,o3,o4,o5}; } + + public Data(Object[] o) { + obs = new Object[o.length]; + System.arraycopy(o, 0, obs, 0, o.length); + } + public Data(Data d, Object[] o) { + obs = new Object[d.obs.length + o.length]; + System.arraycopy(d.obs, 0, obs, 0, d.obs.length); + System.arraycopy(o, 0, obs, d.obs.length, o.length); + } + public Data(Data d1, Data d2) { + obs = new Object[d1.obs.length + d2.obs.length]; + System.arraycopy(d1.obs, 0, obs, 0, d1.obs.length); + System.arraycopy(d2.obs, 0, obs, d1.obs.length, d2.obs.length); + } + + public int len() { return obs.length; } + + public Object o(int at) { return obs[at]; } + public ZZCell c(int at) { return c(obs[at]); } + public String s(int at) { return s(obs[at]); } + public boolean b(int at) { return b(obs[at]); } + public int i(int at) { return i(obs[at]); } + + public static Object o(Object o) { return o; } + public static ZZCell c(Object o) { + if(!(o instanceof ZZCell)) + throw new ZZError("Wrong clang datum "+o+": not a cell"); + return (ZZCell)o; + } + public static String s(Object o) { + if(o instanceof String) + return (String)o; + else if(o instanceof Integer) + return ""+((Integer)o).intValue(); + else if(o instanceof ZZCell) + return ((ZZCell)o).getText(); + else if(o instanceof Boolean) { + if(((Boolean)o).booleanValue()) + return "true"; + else + return "false"; + } else + return o.toString(); // That's right, right? + // throw new ZZError("Wrong clang datum "+o+": not a str"); + } + public static boolean b(Object o) { + if(o instanceof Boolean) + return ((Boolean)o).booleanValue(); + else { + String str = s(o); + if(str.equals("true")) + return true; + else if(str.equals("false")) + return false; + else + throw new ZZError("Wrong clang datum " + o + ": " + + "not a boolean"); + } + } + public static int i(Object o) { + if(o instanceof Integer) + return ((Integer)o).intValue(); + else { + try { + return Integer.parseInt(s(o)); + } catch(NumberFormatException e) { + throw new ZZError("Wrong clang datum " + o + ": " + + "not an integer"); + } + } + } +} diff --git a/Java/clang/ZZClang1.java b/Java/clang/ZZClang1.java new file mode 100644 index 0000000..27927ae --- /dev/null +++ b/Java/clang/ZZClang1.java @@ -0,0 +1,186 @@ +/* +ZZClang1.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.clang; +import org.gzigzag.*; +import java.util.*; + +/** A primitive test version of Clang. + * NOT YET FINISHED! + *

    + * XXX - make use stack frames in the structure + */ + +public class ZZClang1 implements ZZClangContext /* , ZZClangOp */ { +public static final String rcsid = "$Id: ZZClang1.java,v 1.5 2000/10/18 14:35:31 tjl Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + + Hashtable specials; + Hashtable symtab; + ZZCursor cursor; + ZZCell viewspex; + + /** Execute a script in response to user action. + * This means that the language can have special key words to + * pass as parameters the key as a cell with a span etc. + */ + synchronized public void execUserAction(ZZCell code, ZZCell viewspex, + ZZCell clicked, String key) { + try { + specials = new Hashtable(); + if(key!=null) specials.put("UserAction.keyString", key); + if(clicked!=null) + specials.put("UserAction.clickedCell", clicked); + execEnv(code, viewspex); + } finally { + specials = null; + + } + } + + /** Execute a script in a fresh environment. + */ + synchronized public void execEnv(ZZCell code, ZZCell viewspex2) { + symtab = new Hashtable(); + viewspex = viewspex2; + ZZCursor realcursor = new ZZCursorReal(viewspex); + // Speed & space hack + cursor = new ZZCursorVirtual(realcursor.get()); + + exec(code); + + realcursor.set(cursor.get()); + } + + /** Execute starting from a cell. + * Should not be used from outside except in special cases. + */ + synchronized public void exec(ZZCell code) { + p("CLANG exec "+code); + + for(ZZCell current = code; + current != null; + current = current.s("d.2", 1)) { + // Find op. + ZZClangOp op = (ZZClangOp)funcs.get(current.getText()); + p("OP: op"); + if(op==null) + throw new ZZError("Unknown op '"+current.getText()+ "'"); + op.exec(current, cursor, this); + } + + } + +/* + // XXX allow VAR for local variables! + public void exec(ZZCell c, ZZCell it, ZZCell[] params) { + + // First, read the prototype and set the params + ZZCell[] p = c.readRank("d.1", 1, false); + if(p.length > params.length) + throw new ZZError("Insufficient params"); + for(int i=0; i + * However, may also be cloned with a new cursor cell as a subcontext. + * The subcontext is then totally independent of the parent, but starts + * out with the same values if null. + * NOT YET FINISHED! + *

    + * NOTE!!!!!!! getViewCell's viewcell may not be up to date with the ZZCursor + * operations, if code is compiled to pure java for speed. Sync op? + */ + +public interface ZZClangContext { +String rcsid = "$Id: ZZClangContext.java,v 1.3 2000/09/19 10:31:58 ajk Exp $"; + + /** Obtain a reference to the main cursor of this context. + * Ideally, + *

    +     *  clangcontext.getCursor() == ZZCursorReal(clangcontext.getViewcell())
    +     * 
    + * but this may be optimized away, especially for subcontexts, since + * the cursor is used a *lot*. + */ + ZZCursor getCursor(); + /** Obtain a reference to the main viewcell of this context. + */ + ZZCell getViewspex(); + + /** Get a ZZCell that gives the cell that the given parameter + * ultimately refers to. For example, the parameter could be + * a variable in which case this routine returns the cell that + * the variable is set to. Alternatively, the parameter could + * have an expression using cells in which case the result of + * the evaluated expression is given. + * For instance, if the given param is + * @param param The cell that represents the parameter in the clang script. + * @return The actual cell that the given parameter means in this + * context. + */ + ZZCell paramAsCell(ZZCell param); + + /** Get a cursor that represents the variable in the given parameter. + * @param param As for paramAsCell above. + * @return A cursor representing the given variable, or null + * if the param is not a variable. + */ + ZZCursor paramAsCursor(ZZCell param); + + /** Execute the given parameter cell. + * Used to implement routines such as if, case and loops. + * The code given is executed as if on the main level, so all changes + * to the cursor are reflected back after the code. + * @param param As for paramAsCell above. + */ + void execParam(ZZCell param); + + /** Break encapsulation. + * Obtain a special context thingy given to the implementation. + * Nasty optimization hack. + * XXX This should later be done with transient cells. + */ + Object getSpecial(Object which); + +// ZZClangContext getSubcontext(ZZCell startCursor); +} + + diff --git a/Java/clang/ZZClangContextReal.java b/Java/clang/ZZClangContextReal.java new file mode 100644 index 0000000..71be0de --- /dev/null +++ b/Java/clang/ZZClangContextReal.java @@ -0,0 +1,56 @@ +/* +ZZClangContextReal.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.clang; +import org.gzigzag.*; + +class EUNRNBRRV { +} + +/** A real viewspecs -context object for Clang. + */ + +/* +public class ZZClangContextReal implements ZZClangContext { +String rcsid = "$Id: ZZClangContextReal.java,v 1.5 2000/10/18 14:35:31 tjl Exp $"; + + ZZCell viewCell; + ZZClangContextReal(ZZCell vc) { viewCell = vc; } + + public ZZCursor getCursor() { return new ZZCursorReal(viewCell); } + public String getDimString(int n) { return getDim(n).get().getText(); } + + public ZZCursor getDim(int n) { + ZZCell d = viewCell; + for(int i=0; i + * The cursor crs may or may not be the actual cursor of the viewcell + * of the context: it may also be given negwards on d.1 from the object + * to allow ops to act on other cursors easily. + * @param c The cell that made this routine to be called. + * @param crs The main cursor + * @param ctxt The context of the operation. + * @return The it parameter for the next op. + */ + void exec(ZZCell c, ZZCursor crs, ZZClangContext ctxt); + + /* Be mentally prepared for something like + * + * void compile(ZZClangCompiler clc, ZZCell c, ZZClangContext ctxt); + * + * to appear in the future. + */ + + /** Return the name of this operation. + */ + String name(); +} diff --git a/Java/clang/ZZClangOps.pl b/Java/clang/ZZClangOps.pl new file mode 100644 index 0000000..9af1dfc --- /dev/null +++ b/Java/clang/ZZClangOps.pl @@ -0,0 +1,144 @@ +# +# $Id: ZZClangOps.pl,v 1.5 2000/11/03 08:25:16 ajk Exp $ +# +# Generate ZZClangOps.java for clang operations + +$file = $ARGV[0]; +$file = "ZZClangOps.java" if ($file eq ""); +open F, ">$file" or die "Can't open file $file"; +$rcsid = '$Id: ZZClangOps.pl,v 1.5 2000/11/03 08:25:16 ajk Exp $'; +print F <[0]; + @pars = split ' ',$_->[2]; + $npars = @pars; + my $ind = 1; + my %pars = map {($_ => $ind++)} @pars; + + $_->[3] =~ s/\$P\((.*?)\)/(ctxt.paramAsCell(c.s("d.1", $pars{$1}, null)))/g; + $_->[3] =~ s/\$CURS/ crs /g; + + $classes .= " + /** $_->[2] */ + static class $_->[0] implements ZZClangOp { + public String name() { return \"$lcname\"; } + $exec + { + /* if(params.length != $npars) + throw new ZZError(\"Wrong number of params for $lcname, got \"+ + params.length+\", was expecting $npars\"); + */ + $_->[3] + } + } + "; + push @arrays, " new $_->[0]() "; +} + +$ja = join ",\n",@arrays; + +print F <")) + return new Compare(-2); + if(id.equals("<")) + return new Compare(+2); + if(id.equals(">=")) + return new Compare(-1); + if(id.equals("<=")) + return new Compare(+1); + return null; + } + + static public class Plus extends Primitive { + protected Data execute(Data params) { + if(params.len() < 2) miscount(); + int res = params.i(0); + for(int i=1; i 0) { i0 = params.i(0); i1 = params.i(1); } + else { i0 = params.i(1); i1 = params.i(0); } + + boolean res; + if(weight==0) res = i0 == i1; + else if(weight*weight == 4) res = i0 < i1; + else res = i0 <= i1; + return new Data(new Boolean(res)); + } + } +} diff --git a/Java/clang/flowing/Flowing.java b/Java/clang/flowing/Flowing.java new file mode 100644 index 0000000..692ec84 --- /dev/null +++ b/Java/clang/flowing/Flowing.java @@ -0,0 +1,260 @@ +/* +Flowing.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag.module; +import org.gzigzag.*; +import org.gzigzag.flowing.*; +import java.awt.*; + +/** A module interface to Flowing Clang. + */ + +public class Flowing { +public static final String rcsid = "$Id: Flowing.java,v 1.7.8.1 2001/08/16 13:40:44 bfallenstein Exp $"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + + static final void createdebugger(ZZCell debug) { + debug.getSpace().getHomeCell().h("d.2", 1).insert("d.2", 1, debug); + ZZCell normal = debug.N("d.1", 1); + normal.setText("Debug mode"); + ZZCell edit = normal.N("d.1", 1); + edit.setText("Text edit mode"); + ZZCell dim0 = edit.N("d.1", 1); + dim0.setText("d..flowing-frame"); + dim0.N("d.2", 1).setText("d.2"); + dim0.N("d.2", 1).setText("d..flowing-data"); + ZZCell dim1 = dim0.N("d.1", 1); + dim1.setText("d.1"); + dim1.N("d.2", 1).setText("d.clone"); + dim1.N("d.2", 1).setText("d.xeq"); + + // EDIT MODE + + ZZCell c = edit.N("d.2", 1); + c.setText("Tab"); + c.N("d.1", 1).setText("SWITCHOFFCURSMODE"); + normal.insert("d.3", 1, c.s("d.1")); + + c = c.N("d.2", 1); + c.setText("Esc"); + c.N("d.1", 1).setText("SWITCHOFFCURSMODE"); + normal.insert("d.3", 1, c.s("d.1")); + + c = c.N("d.2", 1); + ZZDefaultSpace.findOnSystemlist(c.getSpace(), "Bindings", false) + .s("d.1", 2).s("d.2", 1).insert("d.3", -1, c); + + // NORMAL MODE + + c = normal.N("d.2", 1); + c.setText(" "); + c.N("d.1", 1).setText("Flowing.D-STEP"); + + c = c.N("d.2", 1); + c.setText("Enter"); + c.N("d.1", 1).setText("Flowing.D-JUMP"); + + c = c.N("d.2", 1); + c.setText("Backspace"); + c.N("d.1", 1).setText("UNDO"); + + c = c.N("d.2", 1); + c.setText("Alt-Backspace"); + c.N("d.1", 1).setText("REDO"); + + c = c.N("d.2", 1); + c.setText("q"); + c.N("d.1", 1).setText("QUIT"); + + c = c.N("d.2", 1); + c.setText("Tab"); + c.N("d.1", 1).setText("SWITCHCURSMODE"); + edit.insert("d.3", 1, c.s("d.1")); + + c = c.N("d.2", 1); + c.setText("Left"); + c.N("d.1", 1).setText("CRSR X-"); + + c = c.N("d.2", 1); + c.setText("Right"); + c.N("d.1", 1).setText("CRSR X+"); + + c = c.N("d.2", 1); + c.setText("Up"); + c.N("d.1", 1).setText("CRSR Y-"); + + c = c.N("d.2", 1); + c.setText("Down"); + c.N("d.1", 1).setText("CRSR Y+"); + + c = c.N("d.2", 1); + c.setText("j"); + c.N("d.1", 1).setText("CRSR X-"); + + c = c.N("d.2", 1); + c.setText("l"); + c.N("d.1", 1).setText("CRSR X+"); + + c = c.N("d.2", 1); + c.setText("i"); + c.N("d.1", 1).setText("CRSR Y-"); + + c = c.N("d.2", 1); + c.setText(","); + c.N("d.1", 1).setText("CRSR Y+"); + + c = c.N("d.2", 1); + c.setText("K"); + c.N("d.1", 1).setText("CRSR Z-"); + + c = c.N("d.2", 1); + c.setText("k"); + c.N("d.1", 1).setText("CRSR Z+"); + + c = c.N("d.2", 1); + c.setText("s"); + c.N("d.1", 1).setText("CRSR CX-"); + + c = c.N("d.2", 1); + c.setText("f"); + c.N("d.1", 1).setText("CRSR CX+"); + + c = c.N("d.2", 1); + c.setText("e"); + c.N("d.1", 1).setText("CRSR CY-"); + + c = c.N("d.2", 1); + c.setText("c"); + c.N("d.1", 1).setText("CRSR CY+"); + + c = c.N("d.2", 1); + c.setText("D"); + c.N("d.1", 1).setText("CRSR CZ-"); + + c = c.N("d.2", 1); + c.setText("d"); + c.N("d.1", 1).setText("CRSR CZ+"); + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + if(id.equals("BIND") || id.equals("BINDREAL") || + id.equals("RUN") || id.equals("RUNREAL")) { + ZZCell prog; + if(id.indexOf("BIND") > -1) { + prog = code.s("d.2"); + if(prog == null) + throw new ZZError("Flowing.BIND without program"); + prog = prog.h("d.clone", -1, true); + if(prog == null) + throw new ZZError("Flowing.BIND prog must be cloned"); + } else { + prog = target; + if(prog == null) + prog = ZZCursorReal.get(view.getViewcell()); + } + boolean real = id.indexOf("REAL") > 0; + FlowingClang.run(prog, new Data(cview.getViewcell(), + view.getViewcell(), + key), real); + } else if(id.equals("DEBUG")) { + p("Create debugger:"); + ZZCell prog = + ZZCursorReal.get(view.getViewcell()).getRootclone(); + ZZCell debug = ZZDefaultSpace.findOnSystemlist( + view.getViewcell().getSpace(), "Flowing.Debugger", true); + if(debug.s("d.1") == null) createdebugger(debug); + ZZCell views = ZZDefaultSpace.findOnSystemlist( + view.getViewcell().getSpace(), "Views", false).s("d.1"); + + p("Start program."); + Data d = new Data(cview.getViewcell(), + view.getViewcell(), key); + ZZCell frame = FlowingClang.start(prog, d); + + p("Create windows."); + ZZCell frameview = ZZDefaultSpace.newToplevelView( + prog.getSpace(), "Flowing stack frame", + 20, 20, 400, 500, + views, debug.s("d.1"), + frame, null, + debug.s("d.1", 3).readRank("d.2", 1, true), + ZZUtil.perturb(Color.blue.brighter())); + ZZCursorReal.setColor(frameview, Color.blue.darker()); + + ZZCell progview = ZZDefaultSpace.newToplevelView( + prog.getSpace(), "Flowing program", + 440, 20, 400, 500, + views, debug.s("d.1"), + ZZCursorReal.get(frame), null, + debug.s("d.1", 4).readRank("d.2", 1, true), + ZZUtil.perturb(Color.red.brighter())); + ZZCursorReal.setColor(progview, Color.red.darker()); + + p("Connecting windows."); + frameview.connect("d.ctrlview", 1, progview); + ZZCell framecur = progview.N("d.2", 1); + framecur.setText("Flowing.StackFrame"); + ZZCursorReal.set(framecur, frame); + + p("Update windows."); + ZZWindows.update(); + } else if(id.indexOf("D-") > -1) { + ZZCell framecur = ZZDefaultSpace.findInheritableParam( + view.getViewcell(), "Flowing.StackFrame"); + if(framecur == null) + throw new ZZError("Flowing Clang debugging command on a " + + "non-debug view"); + ZZCell frame = ZZCursorReal.get(framecur); + StackFrameReal sf = new StackFrameReal(frame), nsf; + + if(id.equals("D-STEP")) + nsf = (StackFrameReal)FlowingClang.step(sf, true); + else if(id.equals("D-JUMP")) { + nsf = (StackFrameReal)FlowingClang.jump(sf); + } else + throw new ZZError("Unknown Flowing.XXX code"); + + if(nsf != null) { + if(nsf != sf) { + ZZCursorReal.set(framecur, nsf.main); + ZZCursorReal.set(cview.getViewcell(), nsf.main); + } + ZZCursorReal.set(view.getViewcell(), nsf.getPos()); + } else { + view.getViewcell().h("d.1").delete(); + cview.getViewcell().h("d.1").delete(); + ZZWindows.update(); + ZZCursorReal.delete(view.getViewcell()); + ZZCursorReal.delete(cview.getViewcell()); + } + } else + throw new ZZError("Unknown Flowing.XXX code"); + } + }; + +} + diff --git a/Java/clang/flowing/FlowingClang.java b/Java/clang/flowing/FlowingClang.java new file mode 100644 index 0000000..4b7522d --- /dev/null +++ b/Java/clang/flowing/FlowingClang.java @@ -0,0 +1,219 @@ +/* +FlowingClang.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written for Heraclitus Clang by Tuomas Lukka + * Adaption for Flowing Clang by Benjamin Fallenstein + */ +package org.gzigzag.flowing; +import org.gzigzag.*; +import java.util.*; + +/** A simple (imperative) clang passing values dataflow-like. + * Kind of a cross between a dataflow ("graphical") programming language and + * an assembler. On the one hand we have sequences of instructions, each with + * zero or more in- and output variables; variables are set and read; + * jmp-style branching. + *

    + * However, variables can only be set in one place + * * XXX not any more -- explain XXX + * (they can be set more than + * once by executing the same instruction multiple times). All references to + * the variable are clones; the original (rootclone) is the place where the + * variable is set. This means when you view d.clone, you can see how the + * data "flows" through the program (hence the language's name). + *

    + * Execution strictly proceeds on d.xeq. There are no blocks: when there's + * nothing more on d.xeq, the call returns. Until then, the return values + * (if any) have to be set. Primitives are called by putting their ID into + * a cell, putting the input values negwards and the variables to take the + * output poswards on d.1 from it. (XXX use a less string-based behavior?) + * Subroutines are called by cloning their maincell. Parameter passing and + * results work the same as with primitives. + *

    + * Primitives and subroutines are passed cells, and return cells. If in + * the "input zone" of for a cell or subroutine (neg on d.1) there's a + * cell which isn't cloned (and thus cannot be read as a variable, because + * it cannot have a value assigned), it is taken as literal and passed to + * the subroutine. Cloned cells (variables) are dereferenced in the stack frame + * for the current routine, which means they have to be set. What's passed to + * the subroutine or primitive is the cell which was formerly assigned to the + * variable, not the variable cell itself. + *

    + * To create a subroutine, create a non-clone cell with the routine's name. + * (Later, you clone this into other code.) Put its input variables + * negwards on d.1. Then put the subroutine on d.xeq. When you're done, + * clone the result variable(s) from the point where you set them in the + * routine to the right of the routine's maincell. + *

    + * To branch, create a cell with a question mark ("?") in a strip, put a value + * (variable or literal, but the latter doesn't make too much sense) in its + * "input zone" (neg on d.1), which contains a boolean value ("true" or "false" + * -- everything else is an error), and put a cell in what would usually be + * its "output zone" (pos on d.1). From there, hang a new strip. If the + * condition is true, execution proceeds on the new strip; if the condition + * is false, execution proceeds on the old strip. + *

    + * Blank cells in a strip are usually just ignored. However, a blank cell at + * the end of a strip works like a goto statement: if there's something + * poswards on d.1, the execution pointer jumps to the endcell on d.1 + * and proceeds execution on d.xeq. This is used when, after branching + * because of some condition, you want to unify your strips (i.e., you + * make a blank cell on the end of each one, connect them on d.1, and + * proceed programming on the posmost cell on d.1). + *

    + * Loops can be constructed by looping ZZ cells. You should take care to + * have a condition somewhere in the loop which can turn true. (XXX break + * infinite loops somehow!) + *

    + * The language only uses the d.1, d.xeq, and d.clone dimensions. The + * combinations d.1/d.xeq, d.1/d.clone, d.1/d.xeq/d.clone, d.1/d.clone/d.xeq + * all make sense to view, especially in the row and column views. + */ + +public class FlowingClang { +public static final String rcsid = "$Id: FlowingClang.java,v 1.7 2000/11/16 20:33:13 bfallenstein Exp $"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + + public static final String dim = "d.xeq"; + + static Hashtable pss = new Hashtable(); + static PrimitiveSet findPrimitiveSet(String set) { + Object o = pss.get(set); + if(o != null) return (PrimitiveSet)o; + try { + o = Class.forName("org.gzigzag.flowing."+set).newInstance(); + } catch(Exception e) { + ZZLogger.exc(e); + return null; + } + if(!(o instanceof PrimitiveSet)) return null; + pss.put(set, o); + return (PrimitiveSet)o; + } + + static Hashtable prims = new Hashtable(); + static Primitive findPrimitive(String s) { + Object o = prims.get(s); + if(o != null) return (Primitive)o; + + int ind = s.indexOf("."); + if(ind < 0) return null; + String set = s.substring(0, ind); + String id = s.substring(ind+1); + PrimitiveSet ps = findPrimitiveSet(set); + Primitive prim = ps.get(id); + if(prim != null) + prims.put(id, prim); + return prim; + } + + public static Data run(ZZCell c, Data d) { return run(c, d, false); } + + public static Data run(ZZCell c0, Data d, boolean real) { + p("Flowing Clang run: "+c0.getText()); + ZZCell c = c0.getRootclone(); + StackFrame frame; + if(real) frame = new StackFrameReal(c.getSpace()); + else frame = new StackFrameVirtual(); + frame.setPos(c); + frame.put(c, d, -1); + StackFrame f = frame; + try { + while(f != null) f = step(f, true); + } catch(Throwable t) { + ZZLogger.exc(t, "Exception in Flowing Clang run. "); + return null; + } + return frame.get(c, +1); + } + + public static ZZCell start(ZZCell c0, Data d) { + StackFrameReal frame = new StackFrameReal(c0.getSpace()); + frame.setPos(c0); + frame.put(c0, d, -1); + return frame.main; + } + + public static StackFrame jump(StackFrame frame) { + StackFrame f = frame; + do { + f = step(f, true); + } while(frame.parentof(f)); + return f; + } + + public static StackFrame step(StackFrame frame, boolean throwerrs) { + ZZCell cur = frame.getPos().s(dim); + if(cur == null) { // RETURN + p("Flowing clang return step"); + StackFrame ret = frame.ret(); + if(ret == null) return null; + ZZCell rpos = ret.getPos(); + ret.put(rpos, frame.get(rpos.getRootclone(), +1), +1); + frame.delete(); + return ret; + } + + p("Flowing Clang step: "+cur.getText()+" ("+cur.getID()+")"); + ZZCell root = cur.h("d.clone", -1, true); + String s = cur.getText(); + if(s.equals("") && root==null) { // GOTO + frame.setPos(cur.h("d.1", 1)); + return frame; + } + + Data d = frame.get(cur, -1); // IF + if(s.equals("?")) { + Primitive.count(d, 1); + if(d.b(0)) cur = cur.h("d.1", 1); + frame.setPos(cur); + return frame; + } + + Primitive p = findPrimitive(s); + if(p != null) { // PRIMITIVE + try { + d = p.execute(d, cur.getSpace()); + } catch(ZZError e) { + if(throwerrs) throw e; + ZZLogger.exc(e, "Exception in Flowing Clang step. "); + return frame; + } + frame.put(cur, d, +1); + frame.setPos(cur); + return frame; + } else if(root != null) { // FUNCTION CALL + frame.setPos(cur); + StackFrame called = frame.call(); + called.put(root, d, -1); + called.setPos(root); + return called; + } else { // UNKNOWN + if(throwerrs) + throw new ZZError("Not a primitive at " + cur.getID() + ": " + + cur.getText()); + ZZLogger.log("Flowing Clang step cannot be executed: Not a " + + "primitive at " + cur.getID() + ": " + cur.getText()); + return frame; + } + } +} + diff --git a/Java/clang/flowing/Primitive.java b/Java/clang/flowing/Primitive.java new file mode 100644 index 0000000..7c6a8a0 --- /dev/null +++ b/Java/clang/flowing/Primitive.java @@ -0,0 +1,64 @@ +/* +Primitive.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag.flowing; +import org.gzigzag.*; + +/** An Flowing Clang primitive. + */ + +public abstract class Primitive { +String rcsid = "$Id: Primitive.java,v 1.3 2000/10/13 13:52:24 bfallenstein Exp $"; + + // In subclasses, override one of the following two: + protected Data execute(Data params) { return null; } + public Data execute(Data params, ZZSpace space) { + return execute(params); + } + + static public void count(Data pars, int n) { + if(n != pars.len()) miscount(); + } + static public void miscount() { throw new ZZError("Wrong parameter count"); } + + /** Read a direction or step count from a parameter array. + * If the pos is out of the bounds of the array, +1 is assumed, so that + * the dir can optionally be left out. + *

    + * (This, obviously, is just a convenience function.) + */ + static int readsteps(Data pars, int pos) { + if(pos < pars.len()) { + String stepstr = pars.s(pos); + if(stepstr.equals("+")) + return 1; + else if(stepstr.equals("-")) + return -1; + else + return pars.i(pos); + } else { + return 1; + } + } +} + + diff --git a/Java/clang/flowing/PrimitiveSet.java b/Java/clang/flowing/PrimitiveSet.java new file mode 100644 index 0000000..c8d231c --- /dev/null +++ b/Java/clang/flowing/PrimitiveSet.java @@ -0,0 +1,34 @@ +/* +PrimitiveSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka (for Heraclitus Clang) + */ +package org.gzigzag.flowing; +import org.gzigzag.*; + +/** A set of Flowing Clang primitives. + */ + +public abstract class PrimitiveSet { +String rcsid = "$Id: PrimitiveSet.java,v 1.3 2000/10/13 13:52:24 bfallenstein Exp $"; + public abstract Primitive get(String id); +} + + diff --git a/Java/clang/flowing/StackFrame.java b/Java/clang/flowing/StackFrame.java new file mode 100644 index 0000000..966093a --- /dev/null +++ b/Java/clang/flowing/StackFrame.java @@ -0,0 +1,117 @@ +/* +StackFrame.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag.flowing; +import org.gzigzag.*; + +/** A stack frame for Flowing Clang. + */ + +public abstract class StackFrame { +String rcsid = "$Id: StackFrame.java,v 1.5 2000/11/16 20:33:13 bfallenstein Exp $"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + + // METHODS TO BE IMPLEMENTED BY SUBCLASSES + + /** Get the value associated with a cell. */ + public abstract Object getSingle(ZZCell c); + + /** Set the value associated with a cell. + * @param d The Data object in which the value to be set is found. + * @param at The value's position in the Data object. + */ + public abstract void setSingle(ZZCell c, Data d, int at); + + /** Get position of instruction pointer. */ + public abstract ZZCell getPos(); + /** Set position of instruction pointer. */ + public abstract void setPos(ZZCell c); + + /** Create a lower-level stackframe. */ + public abstract StackFrame call(); + + /** Return true if this stack frame is parent of given stack frame. */ + public abstract boolean parentof(StackFrame sf); + + /** Return to the next higher stackframe (disconnects this (lower) frame). + * Also sets instruction pointer to null, but keeps the values associated + * with cells, so that the returned data can be read. Call delete() when + * you're done with the values. + */ + public abstract StackFrame ret(); + + /** Delete the cells associated with the stackframe, if any. + * This renders the values of a structural stackframe inaccessible. + */ + public void delete() {} + + // METHODS StackFrame PROVIDES + + private static final ZZCell[] reverse(ZZCell[] arr) { + ZZCell[] res = new ZZCell[arr.length]; + for(int i=0; i 3) miscount(); + int steps = readsteps(params, 2); + String dim = params.s(1); + return new Data(params.c(0).s(dim, steps)); + } + } + + static public class End extends Primitive { + protected Data execute(Data params) { + if(params.len() < 2 || params.len() > 3) miscount(); + String dim = params.s(1); + return new Data(params.c(0).h(dim, readsteps(params, 2))); + } + } + + static public class Find extends Primitive { + protected Data execute(Data params) { + if(params.len() < 3 || params.len() > 4) miscount(); + String dim = params.s(1), txt; int dir; + if(params.len() == 3) { + dir = 1; + txt = params.s(2); + } else { + dir = readsteps(params, 2); + txt = params.s(3); + } + ZZCell c = params.c(0).findText(dim, dir, txt); + return new Data(c); + } + } + + static public class Original extends Primitive { + protected Data execute(Data params) { + count(params, 1); + return new Data(params.c(0).getRootclone()); + } + } + + static public class Cross extends Primitive { // i.e., intersect + protected Data execute(Data params) { + if(params.len() != 4 && params.len() != 6) miscount(); + ZZCell c0, c1; + String dim0, dim1; + int dir0, dir1; + + if(params.len() == 4) { + c0 = params.c(0); c1 = params.c(2); + dim0 = params.s(1); dim1 = params.s(3); + dir0 = 1; dir1 = 1; + } else { + c0 = params.c(0); c1 = params.c(3); + dim0 = params.s(1); dim1 = params.s(4); + dir0 = readsteps(params, 2); dir1 = readsteps(params, 5); + } + p("CROSS: "+c0.getText()+" "+dim0+" "+dir0+" "+ + c1.getText()+" "+dim1+" "+dir1); + return new Data(c0.intersect(dim0, dir0, c1, dim1, dir1)); + } + } + + static public class HomeCell extends Primitive { + public Data execute(Data params, ZZSpace space) { + count(params, 0); + return new Data(space.getHomeCell()); + } + } + + static public class Connect extends Primitive { + protected Data execute(Data params) { + if(params.len() < 3 || params.len() > 4) miscount(); + if(params.len() == 3) + params.c(0).connect(params.s(1), params.c(2)); + else + params.c(0).connect(params.s(1), readsteps(params, 2), + params.c(3)); + return null; + } + } + + static public class Insert extends Primitive { + protected Data execute(Data params) { + if(params.len() < 3 || params.len() > 4) miscount(); + if(params.len() == 3) + params.c(0).insert(params.s(1), 1, params.c(2)); + else + params.c(0).insert(params.s(1), readsteps(params, 2), + params.c(3)); + return null; + } + } + + static public class Disconnect extends Primitive { + protected Data execute(Data params) { + if(params.len() < 2 || params.len() > 3) miscount(); + params.c(0).disconnect(params.s(1), readsteps(params, 2)); + return null; + } + } + + static public class Hop extends Primitive { + protected Data execute(Data params) { + if(params.len() < 2 || params.len() > 3) miscount(); + params.c(0).hop(params.s(1), readsteps(params, 2)); + return null; + } + } + + static public class New extends Primitive { + public Data execute(Data params, ZZSpace space) { + if(params.len() == 1 || params.len() > 3) miscount(); + if(params.len() == 0) + return new Data(space.getHomeCell().N()); + else { + String dim = params.s(1); + return new Data(params.c(0).N(dim,readsteps(params, 2))); + } + } + } + + static public class Clone extends Primitive { + protected Data execute(Data params) { + count(params, 1); + return new Data(params.c(0).zzclone()); + } + } + + static public class Delete extends Primitive { + protected Data execute(Data params) { + count(params, 1); + params.c(0).delete(); + return null; + } + } + + static public class Same extends Primitive { + protected Data execute(Data params) { + count(params, 1); + return params; + } + } +} diff --git a/Java/clang/flowing/X.java b/Java/clang/flowing/X.java new file mode 100644 index 0000000..b0585a6 --- /dev/null +++ b/Java/clang/flowing/X.java @@ -0,0 +1,138 @@ +/* +X.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag.flowing; +import org.gzigzag.*; +import java.util.*; + +/* + * The "X" (Cell Text) primitive set for Flowing clang. + */ + +public class X extends PrimitiveSet { +public static final String rcsid = "$Id: X.java,v 1.4 2000/10/20 15:16:54 bfallenstein Exp $"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + + public Primitive get(String id) { + if(id.equals("SET")) + return new Set(); + if(id.equals("+")) + return new Concat(); + if(id.equals("=")) + return new Equals(); + if(id.equals("LEN")) + return new Len(); + if(id.equals("PART")) + return new Part(); + if(id.equals("FIND")) + return new Find(); + if(id.equals("PUICOPY")) + return new PUICopy(); + if(id.equals("PUIPASTE")) + return new PUIPaste(); + if(id.equals("LOG")) + return new Log(); + return null; + } + + static public class Set extends Primitive { + protected Data execute(Data params) { + count(params, 2); + params.c(0).setText(params.s(1)); + return null; + } + } + + static public class Concat extends Primitive { + protected Data execute(Data params) { + if(params.len() < 2) miscount(); + String s = ""; + for(int i=0; i 3) miscount(); + String txt = params.s(0); int start = params.i(1); + if(params.len() == 2) { + txt = txt.substring(start); + } else { + txt = txt.substring(start, params.i(2)); + } + return new Data(txt); + } + } + + static public class Find extends Primitive { + protected Data execute(Data params) { + if(params.len() < 2 || params.len() > 3) miscount(); + String txt = params.s(0), sub = params.s(1); + int start; + if(params.len() == 3) start = params.i(2); + else start = 0; + return new Data(new Integer(txt.indexOf(sub, start))); + } + } + + static public class PUICopy extends Primitive { + protected Data execute(Data params) { + count(params, 1); + ZZUtil.puiCopy(params.s(0)); + return null; + } + } + + static public class PUIPaste extends Primitive { + public Data execute(Data params, ZZSpace space) { + count(params, 0); + return new Data(ZZUtil.puiGetClipText()); + } + } + + static public class Log extends Primitive { + protected Data execute(Data params) { + count(params, 1); + ZZLogger.log(params.s(0)); + return null; + } + } +} diff --git a/Java/clang/heraclitus/HeraclitusClang.java b/Java/clang/heraclitus/HeraclitusClang.java new file mode 100644 index 0000000..261e22c --- /dev/null +++ b/Java/clang/heraclitus/HeraclitusClang.java @@ -0,0 +1,108 @@ +/* +HeraclitusClang.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.heraclitus; +import org.gzigzag.*; +import java.util.*; + +/** A simple execution-based clang. + * Based on a cascading interpreter model, like #! in unix. + * Executables are given as parameters the cell they were referred + * to in (for structural params) and another cell, the parameter. + */ + +public class HeraclitusClang { +public static final String rcsid = "$Id$"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + + static Hashtable pss = new Hashtable(); + static PrimitiveSet findPrimitiveSet(String set) { + Object o = pss.get(set); + if(o != null) return (PrimitiveSet)o; + try { + o = Class.forName("org.gzigzag.heraclitus."+set).newInstance(); + } catch(Exception e) { + ZZLogger.exc(e); + return null; + } + if(!(o instanceof PrimitiveSet)) return null; + pss.put(set, o); + return (PrimitiveSet)o; + } + + static Hashtable prims = new Hashtable(); + static Primitive findPrimitive(ZZCell c) { + String s = c.getText(); + Object o = prims.get(s); + if(o != null) return (Primitive)o; + + int ind = s.indexOf("."); + if(ind < 0) return null; + String set = s.substring(0, ind); + String id = s.substring(ind+1); + PrimitiveSet ps = findPrimitiveSet(set); + Primitive prim = ps.get(id); + if(prim != null) + prims.put(id, prim); + return prim; + } + + /** Execute a heraclitus operation. + * @param op This cell gives the operation, either by + * being the clone of a Heraclitus primitive + * or by having its root clone have an "exe-type". + * @param param The parameter to be given for the + * execution. + */ + public static ZZCell execute(ZZCell op, ZZCell param) { + Primitive p = findPrimitive(op); + p("Heraclitus exec: "+p); + if(p == null) { + ZZCell n = op.h("d.clone", -1); + p = findPrimitive(n); + if(p == null) { + ZZCell nx = op.h("d.exe-type", -1, true); + if(nx == null) { + throw new ZZError("No executable primitive"); + } + // The core: create the new langcache level + ZZCell curs1 = op.getHomeCell().N(); + ZZCell curs2 = curs1.N("d.1", 1); + ZZCursorReal.set(curs1, op); + ZZCursorReal.set(curs2, param); + try { + p("Heraclitus recurse: "+nx); + return execute(nx, curs1); + } finally { + // XXX ZZCursorReal -delete as well?!?! + ZZCursorReal.delete(curs1); + ZZCursorReal.delete(curs2); + curs1.delete(); + curs2.delete(); + } + } + } + return p.execute(op, param); + } +} + diff --git a/Java/clang/heraclitus/HeraclitusCommand.zob b/Java/clang/heraclitus/HeraclitusCommand.zob new file mode 100644 index 0000000..a44c6c6 --- /dev/null +++ b/Java/clang/heraclitus/HeraclitusCommand.zob @@ -0,0 +1,79 @@ +/* +HeraclitusCommand.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag; +import java.awt.*; + +/** ZZCommand interface to Heraclitus Clang. + */ +class HeraclitusCommand extends ZZCommand implements ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + static final void pa(String s) { ZZLogger.log(s); } + + STRUCTPARAMS { + /** Heraclitus operation cell. */ + ZZCell op + = null; + } + + INITIALIZE { + if(op == null) + throw new ZZError("Must specify Heraclitus Clang operation!"); + } + + public void exec(ZZCell param) { + throw new ZZError("exec not implemented yet"); + } + + + public void execCallback( + ZZCell target, + ZZView view, + ZZView cview, + String key, + Point pt, + ZZScene xi + ) { + ZZCell curspar = op.N(); + ZZCell curs1 = op.N(); + ZZCell curs2 = curs1.N("d.1", 1); + ZZCursorReal.set(curs1, cview.getViewcell()); + ZZCursorReal.set(curs2, view.getViewcell()); + ZZCursorReal.set(curspar, curs1); + try { + p("Enter heraclitus: "); + org.gzigzag.heraclitus.HeraclitusClang.execute(op, curspar); + p("Exit heraclitus"); + } finally { + ZZCursorReal.delete(curs1); + ZZCursorReal.delete(curs2); + ZZCursorReal.delete(curspar); + curs1.delete(); + curs2.delete(); + curspar.delete(); + } + + } + +} + +// vim: set syntax=java : diff --git a/Java/clang/heraclitus/PS1.java b/Java/clang/heraclitus/PS1.java new file mode 100644 index 0000000..754a7ad --- /dev/null +++ b/Java/clang/heraclitus/PS1.java @@ -0,0 +1,85 @@ +/* +PS1.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.heraclitus; +import org.gzigzag.*; +import java.util.*; + +/** + * The first primitive set for Heraclitus clang. + */ + +public class PS1 implements PrimitiveSet { +public static final String rcsid = "$Id$"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + + public Primitive get(String id) { + if(id.equals("Move1Test")) + return new Move1Test(); + return null; + } + + /** First test: move a HERA1 (see ZZPrimitiveActions) datacursor one + * step pos on d.1. + */ + static public class Move1Test implements Primitive { + public ZZCell execute(ZZCell primitive, ZZCell cursorparam) { + p("Move1test"); + ZZCell c0 = ZZCursorReal.get(cursorparam); + ZZCell c = c0.s("d.1", 1); + ZZCell v = ZZCursorReal.get(c); + ZZCell t0 = ZZCursorReal.get(v); + ZZCell t = t0.s("d.1", 1); + p("M1T: "+cursorparam+" "+c0+" "+c+" "+t0+" "+t); + ZZCursorReal.set(v, t); + return cursorparam; + } + } + + /** A text translator: translates fixed strings into other fixed + * strings. + */ + + + /** Dereference the cursorparameter: expects the cursorparameter + * to point to another cursor, and makes it point to the place + * the other cursor pointed to. + */ + static public class Deref1 implements Primitive { + public ZZCell execute(ZZCell primitive, ZZCell cursorparam) { + ZZCell c = ZZCursorReal.get(cursorparam); + if(c == null) return null; + ZZCursorReal.set(cursorparam, ZZCursorReal.get(c)); + return cursorparam; + } + } + + /** Execute a sequence of cells with the same cursorparam. + */ + static public class Seq1 implements Primitive { + public ZZCell execute(ZZCell primitive, ZZCell cursorparam) { + // ZZCell root = cursorParam. + return cursorparam; + } + } +} diff --git a/Java/clang/heraclitus/Primitive.java b/Java/clang/heraclitus/Primitive.java new file mode 100644 index 0000000..f852745 --- /dev/null +++ b/Java/clang/heraclitus/Primitive.java @@ -0,0 +1,41 @@ +/* +Primitive.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.heraclitus; +import org.gzigzag.*; + +/** An Heraclitus Clang primitive. + * A primitive, just like a subroutine, executes one cell with another + * as a parameter, and returns another cell. + */ + +public interface Primitive { +String rcsid = "$Id$"; + /** Execute this primitive. + * @param instance The cell instance (clone) that was originally + * requested to be executed. + * @param param The parameter given to the execution. + */ + ZZCell execute(ZZCell instance, ZZCell param); +} + + diff --git a/Java/clang/heraclitus/PrimitiveSet.java b/Java/clang/heraclitus/PrimitiveSet.java new file mode 100644 index 0000000..766277c --- /dev/null +++ b/Java/clang/heraclitus/PrimitiveSet.java @@ -0,0 +1,34 @@ +/* +PrimitiveSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.heraclitus; +import org.gzigzag.*; + +/** A set of Heraclitus Clang primitives. + */ + +public interface PrimitiveSet { +String rcsid = "$Id$"; + Primitive get(String id); +} + + diff --git a/Java/clang/thales/DimensionNames.java b/Java/clang/thales/DimensionNames.java new file mode 100644 index 0000000..5c43abb --- /dev/null +++ b/Java/clang/thales/DimensionNames.java @@ -0,0 +1,52 @@ +/* +DimensionNames.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales; + +import org.gzigzag.*; + +/** Parametrized names of Thales Clang special dimensions. This class + allows easy renaming of these dimensions should one become + necessary. */ +class DimensionNames { + // Note: the members should not be final! (Allows substituting + // this class alone to a precompiled GZigZag.) + + // syntax + public static String sequence = "d.thales-sequence"; + public static String literal = "d.thales-literal"; + public static String argument = "d.thales-argument"; + public static String procedure = "d.thales-procedure"; + public static String primitives = "d.thales-internal-primitives"; + public static String primbinding = "d.thales-internal-binding"; + public static String syntaxform = "d.thales-internal-syntactic-form"; + public static String syntaxformlist = "d.thales-internal-syntactic-form-list"; + + // runtime + public static String tasks = "d.thales-rt-active-tasks"; + public static String stack = "d.thales-rt-stack"; + public static String stackptr = "d.thales-rt-stackptr"; + public static String activations = "d.thales-rt-denoter-activations"; + public static String environment = "d.thales-rt-environment"; + public static String applicable = "d.thales-rt-applicable"; + +} + diff --git a/Java/clang/thales/Environment.java b/Java/clang/thales/Environment.java new file mode 100644 index 0000000..82577a1 --- /dev/null +++ b/Java/clang/thales/Environment.java @@ -0,0 +1,109 @@ +/* +Task.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + + +package org.gzigzag.clang.thales.*; + +import org.gzigzag.*; + +/** A runtime environment. It contains runtime instances of cell + denoters. Remember to register/unregister references (that are in + the structure (not Java references)). */ +class Environment implements Refcounted { + private ZZCell cell; + + public Environment(ZZCell cell) { + this.cell = cell.h(DimensionNames.environment); + } + + public Environment(ZZCell firstparam, Environment parent) { + cell = firstparam.N(DimensionNames.activations, 1); + ZZCell prev = cell; + for (ZZCell c = cell.s(DimensionNames.argument, 1); + c != null; + c = c.s(DimensionNames.argument, 1)) { + ZZCell nc = c.N(DimensionNames.activations, 1); + prev.connect(DimensionNames.environment, 1, nc); + prev = nc; + } + if (parent != null) ZZCursorReal.set(first, parent.getCell()); + cell.setReferenceCount("0"); + parent.registerReference(); + } + + public ZZCell getCell() { return cell; } + + protected int getReferenceCount() { + String text = cell.getText(); + return Integer.parseInt(text); + } + + protected void setReferenceCount(int rc) { + cell.setText("" + rc); + } + + public void registerReference() { + setReferenceCount(getReferenceCount() + 1); + } + + public void unregisterReference() { + setReferenceCount(getReferenceCount() - 1); + if (getReferenceCount() < 1) delete(); + } + + public void delete() { + ZZCell parent = ZZCursorReal.get(cell); + ZZCell c = cell; + while (c != null) { + ZZCell tmp = c; + c = c.s(DimensionNames.environment, 1); + tmp.delete(); + } + if (parent != null) parent.unregisterReference(); + } + + protected ZZCell getDenoterInstance(ZZCell denoter) { + ZZCell ecell = cell; + ZZCell rv = null; + while (rv == null) { + rv = denoter.intersect(DimensionNames.activations, 1, + ecell, DimensionNames.environment, 1); + if (rv == null) { + ecell = ZZCursorReal.get(ecell); + if (ecell == null) { + throw new ZZError("accessing inaccessible denoter"); + } + } + } + return rv; + } + + public ZZCell getDenoterValue(ZZCell denoter) { + ZZCell dc = getDenoterInstance(denoter); + return ZZCursorReal.get(dc); + } + + public void setDenoterValue(ZZCell denoter, ZZCell value) { + ZZCell dc = getDenoterInstance(denoter); + ZZCursorReal.set(dc, value); + } + +} diff --git a/Java/clang/thales/Evaluator.java b/Java/clang/thales/Evaluator.java new file mode 100644 index 0000000..1d68c3a --- /dev/null +++ b/Java/clang/thales/Evaluator.java @@ -0,0 +1,62 @@ +/* +Evaluator.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + + +package org.gzigzag.clang.thales.*; + +import org.gzigzag.*; + +public class Evaluator { + + private Task task; + + public Evaluator() { this(null); } + public Evaluator(Task task) { this.task = task; } + + public Environment getCurrentEnvironment() { + return task.getCurrentEnvironment(); + } + + public void setCurrentEnvironment(Environment e) { + task.setCurrentEnvironment(e); + } + + public void request(SyntaxForm sf) { + task.push(sf.getCell()); + sf.registerReference(); + } + + public void finish_eval(SyntaxForm sf) { + task.remove(sf.getCell()); + sf.unregisterReference(); + } + + private final void eval_iter() { + ZZCell c = task.peek(); + SyntaxForm sf = SyntaxForm.rt_instantiate(c, this); + sf.eval_iteration(); + } + + public void eval_iteration() { eval_iter(); } + + public void eval() { while (!task.empty()) eval_iter(); } + +} diff --git a/Java/clang/thales/PrimitiveOperation.java b/Java/clang/thales/PrimitiveOperation.java new file mode 100644 index 0000000..2789240 --- /dev/null +++ b/Java/clang/thales/PrimitiveOperation.java @@ -0,0 +1,32 @@ +/* +PrimitiveOperation.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales; + +import org.gzigzag.*; + +interface PrimitiveOperation { + + int parameterCount(); + + ZZCell invoke(ZZCell[] arguments); + +} diff --git a/Java/clang/thales/README b/Java/clang/thales/README new file mode 100644 index 0000000..59e75c2 --- /dev/null +++ b/Java/clang/thales/README @@ -0,0 +1,4 @@ +This directory contains the reference implementation of Thales Clang. + +Talk to Antti-Juhani Kaijanaho before making any +nontrivial changes. diff --git a/Java/clang/thales/Refcounted.java b/Java/clang/thales/Refcounted.java new file mode 100644 index 0000000..99ea57f --- /dev/null +++ b/Java/clang/thales/Refcounted.java @@ -0,0 +1,28 @@ +/* +Task.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + + +package org.gzigzag.clang.thales.*; + +interface Refcounted { + void registerReference(); + void unregisterReference(); +} diff --git a/Java/clang/thales/SyntaxForm.java b/Java/clang/thales/SyntaxForm.java new file mode 100644 index 0000000..435de4a --- /dev/null +++ b/Java/clang/thales/SyntaxForm.java @@ -0,0 +1,168 @@ +/* +SyntaxForm.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales; + +import org.gzigzag.*; +import java.lang.reflect.*; + +/** Syntax form. Subclasses must have at least two constructors: one + taking a ZZCell as an argument (the cell must be used to deduce + existing runtime state) and another taking two ZZCells as + arguments (the first cell must be used for parsing the expression, + the other cell must be understood to mean the cell that should be + updated to point to the result of the expression). */ +public abstract class SyntaxForm implements Refcounted { + + static protected ZZCell newRT(ZZSpace space, Class cl) { + String name = cl.getName(); + name = name.substring(name.lastIndexOf(".")+1); + ZZCell home = space.getHomecell(); + ZZCell namec = home.findText(DimensionNames.syntaxformlist, 1, name); + if (namec == null) { + namec = home.N(DimensionNames.syntaxformlist, 1); + namec.setText(name); + } + return namec.zzclone(); + } + + static public SyntaxForm rt_instantiate(ZZCell c, Evaluator etor) { + ZZCell sfc = c.h("d.clone"); + + if (sfc == null) throw new ZZError("no d.clone headcell"); + + if (sfc.h(DimensionNames.syntaxformlist) != sfc.getHomecell()) { + throw new ZZError("not in syntax form list"); + } + + Object o; + + try { + Class cl = Class.forName("org.gzigzag.clang.thales.syntaxform" + + name); + Class cellcl = Class.forName("org.gzigzag.ZZCell"); + Constructor ctor = cl.getConstructor(new Class[] { cellcl }); + o = ctor.newInstance(new Object[] { c } ); + } catch (ClassNotFoundException e) { + throw new ZZError("syntax form not found (" + e + ")"); + } catch (InstantiationException e) { + throw new ZZError("problems instantiating syntax form: " + e); + } catch (IllegalAccessException e) { + throw new ZZError("" + e); + } + + if (!(o instanceof SyntaxForm)) throw new InvalidException(); + + SyntaxForm rv = (SyntaxForm) o; + + rv.etor = etor; + + return rv; + } + + static public SyntaxForm code_instantiate(ZZCell code, ZZCell rv, + Evaluator etor) { + ZZCell sfc = code.h(DimensionNames.syntaxform); + + if (sfc == null) throw new ZZError("invalid syntax form"); + + Object o; + + try { + Class cl = Class.forName("org.gzigzag.clang.thales.syntaxform" + + sfc); + Class cellcl = Class.forName("org.gzigzag.ZZCell"); + Constructor ctor = cl.getConstructor(new Class[] { cellcl, cellcl }); + o = ctor.newInstance(new Object[] { c, rv } ); + } catch (ClassNotFoundException e) { + throw new ZZError("syntax form not found (" + e + ")"); + } catch (InstantiationException e) { + throw new ZZError("problems instantiating syntax form: " + e); + } catch (IllegalAccessException e) { + throw new ZZError("" + e); + } + + if (!(o instanceof SyntaxForm)) throw new InvalidException(); + + SyntaxForm rv = (SyntaxForm)o; + rv.etor = etor; + return rv; + } + + private ZZCell base; + private Evaluator etor = null; + + /** Construct oneself using an existing syntax form runtime + cell. */ + protected SyntaxForm(ZZCell c) { + base = c; + } + + /** Construct oneself using a new syntax form runtime cell. */ + protected SyntaxForm(ZZSpace s) { + this(SyntaxForm.newRT(s, this.getClass())); + } + + protected SyntaxForm code_instantiate(ZZCell code, ZZCell rv) { + SyntaxForm.code_instantiate(code, rv, etor); + } + + protected final ZZCell getBaseCell() { return base; } + protected final void requestEval(SyntaxForm sf) { etor.request(sf); } + protected final void finishEval() { etor.finishEval(this); } + protected final void setCurrentEnvironment(Environment e) { + etor.setCurrentEnvironment(e); + } + protected final Environment getCurrentEnvironment() { + return etor.getCurrentEnvironment(); + } + + public abstract void evalIteration(); + + /** Delete the runtime representation unconditionally. */ + protected abstract void delete(); + + private int getReferenceCount() { + String text = cell.getText(); + if (text.equals("")) { + setReferenceCount(0); + return getReferenceCount(); + } + return Integer.parseInt(text); + } + + private void setReferenceCount(int rc) { + cell.setText("" + rc); + } + + public final void registerReference() { + setReferenceCount(getReferenceCount() + 1); + } + + public final void unregisterReference() { + setReferenceCount(getReferenceCount() - 1); + if (getReferenceCount() < 1) { + delete(); + cell.delete(); + } + } + +} diff --git a/Java/clang/thales/Task.java b/Java/clang/thales/Task.java new file mode 100644 index 0000000..77f1d13 --- /dev/null +++ b/Java/clang/thales/Task.java @@ -0,0 +1,81 @@ +/* +Task.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.*; + +import org.gzigzag.*; + +class Task { + private ZZCell cell; + + public Environment getCurrentEnvironment() { + return new Environment(ZZCursorReal.get(cell)); + } + + public void setCurrentEnvironment(Environment e) { + ZZCursorReal.set(cell, e.getCell()); + } + + public void push(ZZCell c) { + ZZCell ct = peek(); + if (ct != null) { + c.connect(DimensionNames.stack, 1, ct); + cell.disconnect(DimensionNames.stackptr, 1); + } + cell.connect(DimensionNames.stackptr, 1, c); + } + + public void pop() { + ZZCell ct = peek(); + if (ct == null) throw ZZError("empty Thales Clang runtime stack"); + ZZCell nt = ct.s(DimensionNames.stack, 1); + cell.disconnect(DimensionNames.stackptr, 1); + if (nt != null) cell.connect(DimensionNames.stackptr, 1, nt); + nt.disconnect(DimensionNames.stack, -1); + } + + public ZZCell peek() { + return cell.s(DimensionNames.stackptr, 1); + } + + public void remove(ZZCell c) { + { + ZZCell nei = c.s(DimensionNames.stackptr, -1); + if (nei.equals(cell)) { + pop(); + return; + } + } + + for (ZZCell i = peek(); i != null && !i.equals(c); + i = i.s(DimensionNames.stack, 1)) { + // nothing + } + if (i == null) throw ZZError("cannot remove that which is not there"); + + c.deleteFromRank(DimensionNames.stack); + } + + public boolean empty(ZZCell c) { + return peek() == null; + } + +} diff --git a/Java/clang/thales/ThalesClang.java b/Java/clang/thales/ThalesClang.java new file mode 100644 index 0000000..908c0f4 --- /dev/null +++ b/Java/clang/thales/ThalesClang.java @@ -0,0 +1,46 @@ +/* +ThalesClang.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.module; + +import org.gzigzag.*; +import java.awt.*; +import org.gzigzag.clang.thales.*; + +public class ThalesClang { + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, + String key, Point pt, ZZScene xi) { + ZZSpace space = code.getSpace(); + if (id.equals("RELOAD")) { + Primitive.readPrimitivesFromStructure(code.getSpace()); + } else if (id.equals("INITIALIZE")) { + Primitive.register(space, "If"); + } else { + throw new ZZError("unknown ThalesClang module command"); + } + } + + }; +} diff --git a/Java/clang/thales/ThalesProgram.zob b/Java/clang/thales/ThalesProgram.zob new file mode 100644 index 0000000..9e4cc4c --- /dev/null +++ b/Java/clang/thales/ThalesProgram.zob @@ -0,0 +1,45 @@ +/* +ThalesProgram.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.*; + +import org.gzigzag.clang.thales.*; + +class ThalesProgram extends ZZCommand implements ZOb { + + STRUCTPARAM { + + ZZCell body; + + } + + public void execCallback( + ZZCell target, + ZZView view, + ZZView cview, + String key, + Point pt, + ZZScene xi + ) { + + } + +} diff --git a/Java/clang/thales/primitives/If.java b/Java/clang/thales/primitives/If.java new file mode 100644 index 0000000..fa183f4 --- /dev/null +++ b/Java/clang/thales/primitives/If.java @@ -0,0 +1,28 @@ +/* +If.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.primitive; + +import org.gzigzag.clang.thales.*; + +public class If extends Primitive { + +} diff --git a/Java/clang/thales/syntaxforms/Abstraction.java b/Java/clang/thales/syntaxforms/Abstraction.java new file mode 100644 index 0000000..e6bba78 --- /dev/null +++ b/Java/clang/thales/syntaxforms/Abstraction.java @@ -0,0 +1,55 @@ +/* +Primitive.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.syntaxform; + +import org.gzigzag.*; +import org.gzigzag.clang.thales.*; + +public class Abstraction extends SyntaxForm { +public static final String rcsid = "$Id: Abstraction.java,v 1.4 2000/10/18 14:35:31 tjl Exp $"; + + // Runtime representation basecell -> rvcc -> bodyc -> envc posward on d.1 + private final class Rep { + public ZZCell rvcc; + public ZZCell rvc; + public ZZCell bodyc; + public ZZCell body; + public ZZCell envc; // pointer to inherited environment + public Environment env; // dereferenced envc + + /** Create from existing structure. */ + public Rep() { + rvcc = getBaseCell().s("d.1", 1); + rvc = ZZCursorReal.get(rvcc); + bodyc = rvcc.s("d.1", 1); + body = ZZCursorReal.get(bodyc); + envc = bodyc.s("d.1", 1); + env = new Environment(ZZCursorReal.get(envc)); + } + + public Rep(ZZCell body, Environment env, ZZCell rvc + + } + + + +} diff --git a/Java/clang/thales/syntaxforms/CellDenoter.java b/Java/clang/thales/syntaxforms/CellDenoter.java new file mode 100644 index 0000000..844a342 --- /dev/null +++ b/Java/clang/thales/syntaxforms/CellDenoter.java @@ -0,0 +1,82 @@ +/* +CellDenoter.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.syntaxform; + +import org.gzigzag.*; +import org.gzigzag.clang.thales.*; + +class CellDenoter extends SyntaxForm { + // Runtime representation: basecell -> rvcc -> instc on d.1 posward + private final class Rep { + public ZZCell rvcc; // pointer to return value pointer + public ZZCell rvc; // dereferenced rvcc + public ZZCell instc; // Pointer to runtime instance of the denoter + public ZZCell inst; // dereferenced instc + + /** Create from existing structure. */ + public Rep() { + rvcc = getBaseCell().s("d.1", 1); + rvc = ZZCursorReal.get(rvcc); + instc = rvcc.s("d.1", 1); + inst = ZZCursorReal.get(instc); + } + + public Rep(ZZCell inst, ZZCell rvc) { + this.rvc = rvc; + this.inst = inst; + rvcc = getBaseCell().N("d.1", 1); + instc = rvcc.N("d.1", 1); + ZZCursorReal.set(rvcc, rvc); + ZZCursorReal.set(instc, inst); + Environment env = new Environment(inst); + env.registerReference(); + } + + public void delete() { + rvcc.delete(); + instc.delete(); + Environment env = new Environment(inst); + env.unregisterReference(); + } + } + + public CellDenoter(ZZCell c, Evaluator etor) { super(c, etor); } + + public CellDenoter(ZZCell expr, ZZCell rvc, Evaluator etor) { + super(SyntaxForm.newRT(rvc.getSpace(), this.getClass()), etor); + Environment env = getCurrentEnvironment(); + ZZCell instance = env.getDenoterInstance(expr); + Rep rep(instance, rvc); + } + + public void evalIteration() { + Rep rep; + ZZCursorReal.set(rep.rvc, ZZCursorReal.get(rep.inst)); + finishEval(); + } + + public void delete() { + Rep rep; + rep.delete(); + } + +} diff --git a/Java/clang/thales/syntaxforms/CellLiteral.java b/Java/clang/thales/syntaxforms/CellLiteral.java new file mode 100644 index 0000000..95fc84b --- /dev/null +++ b/Java/clang/thales/syntaxforms/CellLiteral.java @@ -0,0 +1,75 @@ +/* +CellLiteral.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.syntaxform; + +import org.gzigzag.*; +import org.gzigzag.clang.thales.*; + +class CellLiteral extends SyntaxForm { + // Runtime representation: basecell -> rvcc -> litc on d.1 posward + private final class Rep { + public ZZCell rvcc; // pointer to the return value pointer + public ZZCell rvc; // dereferenced rvcc + public ZZCell litc; // pointer to literal value + + /** Create from existing structure. */ + public Rep() { + rvcc = getBaseCell().s("d.1", 1); + rvc = ZZCursorReal.get(rvcc); + litc = rvcc.s("d.1", 1); + } + + /** Create also a new structure. */ + public Rep(ZZCell lit, ZZCell rvc) { + this.rvc = rvc; + rvcc = getBaseCell().N("d.1", 1); + ZZCursorReal.set(rvcc, rvc); + litc = rvcc.N("d.1", 1); + ZZCursorReal.set(litc, lit); + } + + public void delete() { + rvcc.delete(); + litc.delete(); + } + } + + public CellLiteral(ZZCell c, Evaluator etor) { + super(c, etor); + } + + public CellLiteral(ZZCell expr, ZZCell rvc, Evaluator etor) { + super(SyntaxForm.newRT(rvc.getSpace(), this.getClass()), etor); + Rep rep(ZZCursorReal.get(expr), rvc); + } + + public void evalIteration() { + Rep rep; + ZZCursorReal.set(rep.rvc, ZZCursorReal.get(rep.litc)); + finishEval(); + } + + protected void delete() { + Rep rep; + rep.delete(); + } +} diff --git a/Java/clang/thales/syntaxforms/Primitive.java b/Java/clang/thales/syntaxforms/Primitive.java new file mode 100644 index 0000000..d551a8e --- /dev/null +++ b/Java/clang/thales/syntaxforms/Primitive.java @@ -0,0 +1,191 @@ +/* +Primitive.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.syntaxform; + +import org.gzigzag.*; +import org.gzigzag.clang.thales.*; +import java.util.*; + +public class Primitive extends SyntaxForm { +public static final String rcsid = "$Id: Primitive.java,v 1.7 2000/10/18 14:35:31 tjl Exp $"; + public static boolean dbg = false; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + // Runtime representation basecell -> rvcc -> primc posward on d.1 + private final class Rep { + public ZZCell rvcc; // pointer to return value pointer + public ZZCell rvc; // dereferenced rvcc + public ZZCell primc; // pointer to the primitive cell + public ZZCell prim; // the primitive cell + + /** Create from existing structure. */ + public Rep() { + rvcc = getBaseCell().s("d.1", 1); + rvc = ZZCursorReal.get(rvcc); + primc = rvcc.s("d.1", 1); + prim = ZZCursorReal.get(rvc); + } + + /** Create also a new structure. */ + public Rep(ZZCell prim, ZZCell rvc) { + this.rvc = rvc; + rvcc = getBaseCell().N("d.1", 1); + ZZCursorReal.set(rvcc, rvc); + this.prim = prim; + primc = rvcc.N("d.1", 1); + ZZCursorReal.set(primc, prim); + } + + public void delete() { + rvcc.delete(); + primc.delete(); + } + } + + public Primitive(ZZCell c) { super(c); } + public Primitive(ZZCell expr, ZZCell rvc) { + super(rvc.getSpace()); + Rep rep(expr.h("d.clone", -1), rvc); + } + + public void evalIteration() { + Rep rep; + + ZZCell rv = rep.rvc.N(); + rv.connect(DimensionNames.applicable, 1, rep.prim); + ZZCursorReal.set(rep.rvc, rv); + finishEval(); + } + + public void delete() { + Rep rep; + rep.delete(); + } + + + + static private Hashtable prims = new Hashtable(); + static private Hashtable optocell = new Hashtable(); + + static public PrimitiveOperation get(ZZCell c) { + ZZCell id = c.h("d.clone", -1); + synchronized (prims) { + return (PrimitiveOperation) prims.get(id); + } + } + + static public class PrimitiveProblemException extends ZZError { + public PrimitiveProblemException(String s) { + super(s); + } + } + + static public class DuplicateException extends PrimitiveProblemException { + public DuplicateException() { + this("duplicate Thales Clang primitive cell"); + } + public DuplicateException(String s) { + super(s); + } + } + + static public class InvalidException extends PrimitiveProblemException { + public InvalidException() { + this("invalid Thales Clang primitive cell"); + } + public InvalidException(String s) { + super(s); + } + } + + static private void readAPrimitive(ZZCell c) { + ZZCell op = c.s(DimensionNames.primbinding, 1); + + if (op == null) throw new InvalidException(); + + Object o; + + try { + Class cl = Class.forName("org.gzigzag.clang.thales.primitive." + op.getText()); + o = cl.newInstance(); + } catch (ClassNotFoundException e) { + throw new InvalidException("primitive not found (" + e + ")"); + } catch (InstantiationException e) { + throw new InvalidException("problems instantiating primitive: " + e); + } catch (IllegalAccessException e) { + throw new InvalidException("" + e); + } + + if (!(o instanceof PrimitiveOperation)) throw new InvalidException(); + + // XXX: is this necessary or desirable? + if (optocell.containsKey(o)) throw new DuplicateException(); + + synchronized (prims) { + prims.put(c, o); + optocell.put(o, c); + } + } + + static public void readPrimitivesFromStructure(ZZSpace space) { + ZZCell home = space.getHomeCell(); + + synchronized (prims) { + for (ZZCell c = home.s(DimensionNames.primitives, 1); + c != null; + c = c.s(DimensionNames.primitives, 1)) { + try { + readAPrimitive(c); + } catch (PrimitiveProblemException e) { + pa("" + e); + } + } + } + } + + static public void register(ZZSpace space, String mc) { + ZZCell home = space.getHomeCell(); + + synchronized (prims) { + ZZCell id = home.N(); + ZZCell name = id.N(DimensionNames.primbinding, 1); + + name.setText(mc); + + try { + readAPrimitive(id); + } catch (ZZError e) { + id.delete(); + name.delete(); + throw e; + } + + home.insert(DimensionNames.primitives, 1, id); + } + } + +} + + + + diff --git a/Java/clang/thales/syntaxforms/Sequence.java b/Java/clang/thales/syntaxforms/Sequence.java new file mode 100644 index 0000000..8ea1c38 --- /dev/null +++ b/Java/clang/thales/syntaxforms/Sequence.java @@ -0,0 +1,95 @@ +/* +Sequence.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag.clang.thales.syntaxform; + +import org.gzigzag.*; +import org.gzigzag.clang.thales.*; + +class Sequence extends SyntaxForm { + // Runtime representation: basecell -> rvcc -> tmprc -> csec on + // d.1 posward + private final class Rep { + public ZZCell rvcc; // pointer to return value pointer + public ZZCell rvc; // dereferenced rvcc + public ZZCell tmprc; // temporary holder of component expression results + public ZZCell tmpr; // dereferenced tmprc + public ZZCell csec; // pointer to the current subexpression in code + public ZZCell cse; // current subexpression in code + + /** Create from existing structure. */ + public Rep() { + rvcc = getBaseCell().s("d.1", 1); + rvc = ZZCursorReal.get(rvcc); + tmprc = rvcc.s("d.1", 1); + tmpr = ZZCursorReal.get(tmprc); + csec = tmprc.s("d.1", 1); + cse = ZZCursorReal.get(csec); + } + + /** Create also a new structure. */ + public Rep(ZZCell fse, ZZCell rvc) { + rvcc = getBaseCell().N("d.1", 1); + ZZCursorReal.set(rvcc, rvc); + this.rvc = rvc; + tmprc = rvcc.N("d.1", 1); + tmpr = null; + csec = tmprc.N("d.1", 1); + ZZCursorReal.set(csec, fse); + cse = fse; + } + + public void delete() { + rvcc.delete(); + tmprc.delete(); + csec.delete(); + } + + public Sequence(ZZCell c) { super(c); } + + public Sequence(ZZCell expr, ZZCell rvc) { + super(rvc.getSpace()); + ZZCell fse = expr.s(DimensionNames.sequence, 1); + if (fse == null) { + throw new SyntaxError("sequence must have at least one element"); + } + Rep rep(fse, rvc); + } + + public void evalIteration() { + Rep rep; + + if (rep.cse == null) { + ZZCursorReal.set(rvc, tmpr); + finishEval(); + } + + SyntaxForm sf = code_instantiate(rep.cse, tmprc); + + requestEval(sf); + + ZZCursorReal.set(rep.csec, + rep.cse.s(DimensionNames.sequence, 1)); + } + + } + +} diff --git a/Java/d.java b/Java/d.java new file mode 100644 index 0000000..20b33f5 --- /dev/null +++ b/Java/d.java @@ -0,0 +1,47 @@ +/* +d.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; + +/** A funny hack to allow funny code. + * This class defines names for many of the common dimensions. If + * you have imported the package, you can then refer to d.clone + * as d.clone, without the quotation marks, and the constant in this + * class will be there. + *

    + * It is unfortunate that d.1 cannot be done with this, but this can + * be a blessing since code shouldn't usually be hard-coded to use + * the numbered dimensions. + *

    + * This class may have to be retired once dimensions are cells in order + * to allow different views to work on different dimensions. + * @deprecated Not useful any more. + */ + +public class d { +public static final String rcsid = "$Id: d.java,v 1.8 2000/10/26 18:09:29 tjl Exp $"; + public static final String clone="d.clone"; + public static final String mark="d.mark"; + public static final String cursor="d.cursor"; +// public static final String cursor-cargo="d.cursor-cargo"; + public static final String preflet="d.preflet"; +} diff --git a/Java/dump2java.pl b/Java/dump2java.pl new file mode 100644 index 0000000..7ffb2e1 --- /dev/null +++ b/Java/dump2java.pl @@ -0,0 +1,147 @@ +# +# dump2java.pl +# * +# * Copyright (c) 2000, Ted Nelson and Tuomas Lukka +# * +# * You may use and distribute under the terms of either the GNU Lesser +# * General Public License, either version 2 of the license or, +# * at your choice, any later version. Alternatively, you may use and +# * distribute under the terms of the XPL. +# * +# * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# * the licenses. +# * +# * This software 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 README +# * file for more details. +# * +# */ +# /* +# * Written by Benjamin Fallenstein +# */ +# + +@ARGV == 2 or die "Two params: infile outfile"; + +$outfile = pop @ARGV; +$infile = $ARGV[0]; + +$declare = ""; +$create = ""; + +$str = join '', <>; +#$str =~ + # /HEADER\n\n((?:.+\n)*)\n\nCONTENTS\n\n((?:.+\n)*)\n\nCONNECTIONS\n\n((?:(?:.+\n)*\n)*)\nEND OF FILE/ + # or die("Bad .zzd file: $infile"); + +@parts = split "\n\n\n", $str; +($hdr, $ctnt, $conns) = @parts; + +foreach(split '\n', $hdr) { + ($var, $val) = split ': '; + if($var =~ /^Format/) { + die("Wrong Dump format: $infile") + unless $val == "Dump 2"; + } elsif($var =~ /^Title/) { + $title = $val; + } +} + +sub cref { + my $id = $_[0]; + if($id != 0 || $id eq "0") { + $id = "__cs[$id]"; + } + return $id; +} + +$no = 0; +%nos = (); +foreach(split '\n', $ctnt) { + $_ =~ /^(.*?) (.*)$/; + ($id, $ct) = ($1, $2); + $nos{$id} = $no; + $no++; + + $ct =~ s/"/\\"/; + $create_ctnt .= qq{ "$ct",\n}; + + if($id == 0 && $id ne "0" && $id ne "") { + $declare .= " ZZCell $id;\n"; + $create_vars .= " $id = __ct[$no];"; + } +} + +$dimno = 0; +foreach (split '\n\n', $conns) { + ($dim, @parts) = split '\n'; + $dim =~ s/"/\\"/; + $create_dims .= qq{ "$dim",\n}; + + foreach(@parts) { + ($id1, $id2) = split ' '; + $create_conns .= " { $dimno, " . + $nos{$id1} . ", " . $nos{$id2} . + " },\n"; + } + + $dimno++; +} + +$nu = <$outfile" or die "No out: '$outfile'"; +print OUT $nu; +#print $nu; +close OUT; diff --git a/Java/errors/MissingTermError.java b/Java/errors/MissingTermError.java new file mode 100644 index 0000000..1ea6440 --- /dev/null +++ b/Java/errors/MissingTermError.java @@ -0,0 +1,30 @@ +/* +MissingTermError.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein. + */ + +package org.gzigzag; + +import org.gzigzag.*; + +/** An error to indicate a term in a clang program is missing. + */ +public class MissingTermError extends SyntaxError { + public MissingTermError(String s) { super(s); } +} diff --git a/Java/errors/SyntaxError.java b/Java/errors/SyntaxError.java new file mode 100644 index 0000000..45adc03 --- /dev/null +++ b/Java/errors/SyntaxError.java @@ -0,0 +1,28 @@ +/* +SyntaxError.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho. + */ + +package org.gzigzag; + +import org.gzigzag.*; + +public class SyntaxError extends ZZError { + public SyntaxError(String s) { super(s); } +} diff --git a/Java/errors/ZZConnectWouldBreakError.java b/Java/errors/ZZConnectWouldBreakError.java new file mode 100644 index 0000000..8717087 --- /dev/null +++ b/Java/errors/ZZConnectWouldBreakError.java @@ -0,0 +1,34 @@ +/* +ZZConnectWouldBreakError.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; + +/** A connect operation would break an existing connection and is not + * allowed. + */ + +public class ZZConnectWouldBreakError extends ZZError { +public static final String rcsid = "$Id: ZZConnectWouldBreakError.java,v 1.3 2000/09/19 10:31:59 ajk Exp $"; + public ZZConnectWouldBreakError(String s) { super(s); } +} + diff --git a/Java/errors/ZZError.java b/Java/errors/ZZError.java new file mode 100644 index 0000000..7296565 --- /dev/null +++ b/Java/errors/ZZError.java @@ -0,0 +1,42 @@ +/* +ZZError.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +/* + * Things can happen to browsers in magical libraries that make + * having your face pulled off by tentacled monstrosities from + * the Dungeon Dimensions seem a mere light massage by comparison. + * - Terry Pratchett, Mort, p. 153 + */ + +package org.gzigzag; + +/** A relatively recoverable ZigZag error. + * Later on, this should be subclassed and specialized as necessary. + * Note that catching this is ok - it's just that normally + * when it happens, we want to just let it unwind the stack without + * having to declare "throws ZZException" everywhere. + */ + +public class ZZError extends Error { +public static final String rcsid = "$Id: ZZError.java,v 1.4 2000/09/19 10:31:59 ajk Exp $"; + public ZZError(String s) { super(s); } +} diff --git a/Java/errors/ZZFatalError.java b/Java/errors/ZZFatalError.java new file mode 100644 index 0000000..e0d98a8 --- /dev/null +++ b/Java/errors/ZZFatalError.java @@ -0,0 +1,40 @@ +/* +ZZFatalError.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +/* + * Things can happen to browsers in magical libraries that make + * having your face pulled off by tentacled monstrosities from + * the Dungeon Dimensions seem a mere light massage by comparison. + * - Terry Pratchett, Mort, p. 153 + */ + +package org.gzigzag; + +/** An irrecoverable ZZ error. Some consistency error that has + * made it dangerous to proceed: execution should be ceased at once. + * + */ + +public class ZZFatalError extends Error { +public static final String rcsid = "$Id: ZZFatalError.java,v 1.3 2000/09/19 10:31:59 ajk Exp $"; + public ZZFatalError(String s) { super(s); } +} diff --git a/Java/errors/ZZInfiniteLoop.java b/Java/errors/ZZInfiniteLoop.java new file mode 100644 index 0000000..5881e87 --- /dev/null +++ b/Java/errors/ZZInfiniteLoop.java @@ -0,0 +1,33 @@ +/* +ZZInfiniteLoop.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; + +/** An operation caused an infinite loop. + */ + +public class ZZInfiniteLoop extends ZZError { +public static final String rcsid = "$Id: ZZInfiniteLoop.java,v 1.3 2000/09/19 10:31:59 ajk Exp $"; + public ZZInfiniteLoop(String s) { super(s); } +} + diff --git a/Java/errors/ZZInvalidCursorPositionError.java b/Java/errors/ZZInvalidCursorPositionError.java new file mode 100644 index 0000000..1847dac --- /dev/null +++ b/Java/errors/ZZInvalidCursorPositionError.java @@ -0,0 +1,34 @@ +/* +ZZInvalidCursorPositionError.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; + +/** Tried to move a cursor to a place that can't have cursors on it. + * @deprecated Cursors can be anywhere, now. + */ + +public class ZZInvalidCursorPositionError extends ZZError { +public static final String rcsid = "$Id: ZZInvalidCursorPositionError.java,v 1.4 2000/10/26 18:09:29 tjl Exp $"; + public ZZInvalidCursorPositionError(String s) { super(s); } +} + diff --git a/Java/errors/ZZInvalidDimensionError.java b/Java/errors/ZZInvalidDimensionError.java new file mode 100644 index 0000000..f3e473a --- /dev/null +++ b/Java/errors/ZZInvalidDimensionError.java @@ -0,0 +1,33 @@ +/* +ZZInvalidDimensionError.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; + +/** A given dimension is invalid. + */ + +public class ZZInvalidDimensionError extends ZZError { +public static final String rcsid = "$Id: ZZInvalidDimensionError.java,v 1.3 2000/09/19 10:31:59 ajk Exp $"; + public ZZInvalidDimensionError(String s) { super(s); } +} + diff --git a/Java/exp/rast/vanishing.view b/Java/exp/rast/vanishing.view new file mode 100644 index 0000000..7d2f3bd --- /dev/null +++ b/Java/exp/rast/vanishing.view @@ -0,0 +1,107 @@ +# An attempt to describe vanishingview using +# CDTree raster in a hypothetical language. +# +# Python-like: syntax includes spaces +# a . b = vector product +# :f(...) = one-directional external function + +CDTree(3) + +Param + # the fraction the gap between cells is from the size + # of the larger one + float gfrac + + # Alignment point of node at given size + vec2 :align(node, vec2) + + # the size for node given fraction. + # If node is null, return a reasonable constant one + vec2 :fsize(node, float) + + # Reverse perspective + float revper + + # Whether cells' sizes should stretch + boolean varsize + + # How much to shrink cells along different axes + float shrink0 + float shrink1 + float shrink2 + + # The fract of the initial cell + float initmul + +Var + # The location of a cell + vec2 v(i) + + # The location of the point of alignment of a cell + vec2 av(i) + + # The location of a cell, without revper having been applied + vec2 rv(i) + + # The location of cell's alignpoint, without revper having been applied + vec2 rav(i) + + # Fraction for the font size + float fract(i) + + # Size of the cell + vec2 size(i) + + # The x and y gaps + vec2 gap(i) + + # The gap size between two cells. + vec2 gapb(i,j) + +Local(i) + av(i) = v(i) + :align(i, size(i)) + v(i) = revper * rv(i) + av(i) = revper * rav(i) + + if(varsize) + size(i) = :fsize(i, fract) + else + size(i) = :fsize(null, fract) + + gap(i) = gfrac * size(i) + +Neighbour + + # The shrinking size away from center + + out_0(i,j) => + fract(j) = shrink0 * fract(i) + out_1(i,j) => + fract(j) = shrink1 * fract(i) + out_2(i,j) => + fract(j) = shrink2 * fract(i) + + # Propagate the gap to between the cells + out_*(i,j) => + gapb(i,j) = gap(i) + + + # The positions of the cells + + pos_0(i,j) => + rv(j) . X = v(i) + size(i) . X + gapb(i,j) . X + rav(j) . Y = av(i) . Y + + pos_1(i,j) => + rv(j) . Y = v(i) + size(i) . Y + gapb(i,j) . Y + rav(j) . X = av(i) . X + + # We do z axis in a simplistic way until tested + pos_2(i,j) => + rv(j) = v(i) + size(i) + gapb(i,j) + +Init + av(origin) = vec2(0,0) + fract(origin) = initmul + + diff --git a/Java/flob/ArrowDecor.java b/Java/flob/ArrowDecor.java new file mode 100644 index 0000000..73bf477 --- /dev/null +++ b/Java/flob/ArrowDecor.java @@ -0,0 +1,134 @@ +/* +ArrwDecor.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** Arrows. + */ + +public class ArrowDecor extends CoordDecor { +public static final String rcsid = "$Id: ArrowDecor.java,v 1.4 2000/10/26 18:09:29 tjl Exp $"; + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + Color color; + + /** A simple class that knows how to efficiently build + * ArrowDecors. + */ + static public class Builder extends CoordDecor.Builder { + Color col; + public Builder(FlobSet into, Color col) { + super(into); + this.col = col; + } + /** Make a line. + */ + public final void ar(int x0, int y0, int x1, int y1) { + makeRoom(4); + p[curp] = x0; + p[curp+1] = y0; + p[curp+2] = x1; + p[curp+3] = y1; + curp += 4; + } + protected Renderable create() { + return new ArrowDecor(p, np, col, d); + } + + } + + public ArrowDecor(int[] coords, int n, int d) { + this(coords, n, null, d); + } + + /** Usual constructor. + * @param coords The coordinates for the lines, given as + * quadruplets x1, y1, x2, y2. + */ + public ArrowDecor(int[] coords, int n, Color color, int d) { + super(coords, n, d); + this.color = color; + } + + public ArrowDecor(int x1, int y1, int x2, int y2, Color color, int d) { + super(null, 4, d); + this.coords = new int[] { + x1, y1, x2, y2 + }; + this.color = color; + this.d = d; + } + + public void render(Graphics g) { + Color old = null; + if(color != null) { + old = g.getColor(); + g.setColor(color); + } + + for(int i=0; i+3 s.length()) { + // XXX What to do? + return x + xoffs + h + fm.stringWidth(s); + } + return x + xoffs + h + fm.stringWidth(s.substring(0, ind)) ; + } + + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + int ty = my + (mh-fh)/2 + fasc; + Color bu = g.getColor(); + g.setColor(ballColor != null ? ballColor : Color.white); + g.fillOval(mx+yoffs, my+yoffs, mh-2*yoffs, mh-2*yoffs); + g.setFont(f); + int start = 0; + int end = -1; + while (end < s.length()) { // Split into lines + + do { + end = s.indexOf(' ', end + 1); + if (end == -1) break; + } while (fm.stringWidth(s.substring(start, end)) < mw); + + if (end == -1) + end = s.length(); + if (start < end) { + String line = s.substring(start, end); + + g.setColor(bgColor); + if (false && start != 0) { + g.fillRect(mx+xoffs + h - 2, ty - (fasc - (fh-fasc)), fm.stringWidth(line), fasc-(fh-fasc)); + } else { + g.drawString(line, mx+xoffs + h - 1, ty - 1); + g.drawString(line, mx+xoffs + h + 2, ty + 2); + } + + g.setColor(Color.white); + g.drawString(line, mx+xoffs + h + 1, ty + 1); + + g.setColor(bu); + g.drawString(line, mx+xoffs + h, ty); + ty += fasc; + } + start = end + 1; + } + + g.setColor(bu); + g.drawOval(mx+yoffs, my+yoffs, mh-2*yoffs, mh-2*yoffs); + } + + public BallCell(int x, int y, int d, int w, int h, + ZZCell c, ZZCell strCell, String s, + Font f, FontMetrics fm, FlobSet fs) { + super(x, y, d, w, h, c); + + // Not true, since c can be the flob cell and d the referring + // cell. + // this.s = c.getText(); + + this.s = (s==null? "" : s); + this.strCell = strCell; + + this.f = f; + this.fm = fm; + + this.fh = fm.getAscent()+fm.getDescent(); + this.fasc = fm.getAscent()+fm.getLeading(); + this.sw = fm.stringWidth(this.s); + + this.bgColor = fs.getBackground(); + } + + public Object hit(int x0, int y0) { + if(!insideRect(x0, y0)) return null; + // Search for the right position in the string. + // We return a virtual cursor. + int ind = ZZUtil.findStringHit(s, x0-x-xoffs-h, fm); + + return new ZZCursorVirtual(strCell, ind); + } + + public Point getCenter(Point p) { + p.x = x + h/2; + p.y = y + h/2; + return p; + } + +} + + diff --git a/Java/flob/BeamDecor.java b/Java/flob/BeamDecor.java new file mode 100644 index 0000000..3a7794d --- /dev/null +++ b/Java/flob/BeamDecor.java @@ -0,0 +1,107 @@ +/* +BeamDecor.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A class for drawing beam decorations. + * Beams are currently irregular octagons. + * NOTE: Beams are rendered in reverse order: the first beam put in here + * becomes the topmost. + */ + +public class BeamDecor extends CoordDecor { +public static final String rcsid = "$Id: BeamDecor.java,v 1.4 2000/09/19 10:31:59 ajk Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + Color[] colors; + + /** A simple class that knows how to efficiently build + * these things. + */ + static public class Builder extends CoordDecor.Builder { + Color []col; + public Builder(FlobSet into) { + super(into); + } + + protected void makeRoom(int l) { + if(col != null && nth >= col.length) + endl(); + super.makeRoom(l); + } + + protected void alloc() { + super.alloc(); + col = new Color[np/16]; + } + /** Make a beam. + * Coords: first 8x, then 8y. + */ + public final void b(int []xy, Color c) { + makeRoom(16); + p("beam: "+p+" "+col+" "+curp+" "+nth); + for(int i=0; i<16; i++) + p[curp+i] = xy[i]; + col[nth] = c; + curp += 16; + nth++; + } + protected Renderable create() { + Color[] col2 = col; + col = null; + return new BeamDecor(p, np, d, col2); + } + + } + + public BeamDecor(int[] coords, int n, int d, Color[] cols) { + super(coords, n, d); + this.colors = cols; + } + + + public void render(Graphics g) { + Color old = null; + old = g.getColor(); + + int[] x = new int[8]; + int[] y = new int[8]; + for(int i=(n-16)-n%16; i>=0; i-=16) { + for(int k = 0; k<8; k++) + x[k] = coords[i+k]; + for(int k = 0; k<8; k++) + y[k] = coords[i+8+k]; + + g.setColor(colors[i/16]); + g.fillPolygon(x, y, 8); + } + + g.setColor(old); + } + +} diff --git a/Java/flob/BoxType.java b/Java/flob/BoxType.java new file mode 100644 index 0000000..b2ca204 --- /dev/null +++ b/Java/flob/BoxType.java @@ -0,0 +1,90 @@ +/* +BoxType.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * Copyright (c) 2001, Benja Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benja Fallenstein + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A type of boxes to be drawn around vobs (like the CellBgFlob backgrounds). + * Default: render nothing. + */ + +public class BoxType { +public static final String rcsid = "$Id: BoxType.java,v 1.2 2001/03/18 17:50:16 bfallenstein Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + protected Color bg = Color.white; + public void setBg(Color c) { if( c != null ) bg = c; } + + protected void renderBg(Graphics g, BoxedFlob f, int mx, int my, + int md, int mw, int mh) {} + + protected void renderFrame(Graphics g, BoxedFlob f, int mx, int my, + int md, int mw, int mh) {} + + /** Render the background behind the flob. + */ + public void renderBg(Graphics g, Flob f) { + renderBg(g, (BoxedFlob)f, f.x, f.y, f.d, f.w, f.h); + } + + /** Render the frame around the flob. + */ + public void renderFrame(Graphics g, Flob f) { + renderFrame(g, (BoxedFlob)f, f.x, f.y, f.d, f.w, f.h); + } + + /** Render the interpolated background behind the flob. + */ + public void renderBg(Graphics g, Flob f, float fract) { + // XXX the interpolation path isn't necessarily linear! + Flob r = f.interpTo; + renderBg(g, (BoxedFlob)f, + (int)(f.x + fract*(r.x-f.x)), + (int)(f.y + fract*(r.y-f.y)), + (int)(f.d + fract*(r.d-f.d)), + (int)(f.w + fract*(r.w-f.w)), + (int)(f.h + fract*(r.h-f.h)) + ); + } + + /** Render the interpolated frame around the flob. + */ + public void renderFrame(Graphics g, Flob f, float fract) { + // XXX the interpolation path isn't necessarily linear! + Flob r = f.interpTo; + renderFrame(g, (BoxedFlob)f, + (int)(f.x + fract*(r.x-f.x)), + (int)(f.y + fract*(r.y-f.y)), + (int)(f.d + fract*(r.d-f.d)), + (int)(f.w + fract*(r.w-f.w)), + (int)(f.h + fract*(r.h-f.h)) + ); + } +} + + diff --git a/Java/flob/BoxedFlob.java b/Java/flob/BoxedFlob.java new file mode 100644 index 0000000..ae82aac --- /dev/null +++ b/Java/flob/BoxedFlob.java @@ -0,0 +1,83 @@ +/* +BoxedFlob.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * Copyright (c) 2001, Benja Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, adapted by Benja Fallenstein + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A flob which gets rendered by FlobSet with a background. + * XXX support for different shapes than rectangular? + * XXX replace Colorer entirely by this? + * XXX renderer must know whether background is transparent! + * XXX move needsBox here and default to true?!? replace by instanceof Boxed? + */ + +public class BoxedFlob extends Flob implements Colorer { +public static final String rcsid = "$Id: BoxedFlob.java,v 1.1 2001/03/20 11:08:36 ajk Exp $"; + public static final boolean dbg = true; +// static final void p(String s) { if(dbg) System.out.println(s); } +// static final void pa(String s) { System.out.println(s); } + +// XXX need this? boolean drawBorder = true; + + public boolean needsBox() { return true; } + + int nsolids = 0; + Color[] solids; + protected Color bg = Color.white; + + public Object hit(int x0, int y0) { + if( x0 >= x && y0 >= y && x0 < x+w && y0 < y+h ) + return c; + return null; + } + + public void setBg(Color c){ if( c != null ) bg = c; } + + /** Adds one more solid color to be drawn inside + * the cell. + */ + public boolean addColor(Color c) { + if(solids == null || nsolids >= solids.length) { + Color[] n= new Color[nsolids + 10]; + if(solids != null) System.arraycopy(solids, 0, n, 0, nsolids); + solids = n; + } + solids[nsolids++] = c; + return false; + } + /** The currently put solid colors. + * null = none. There may be null references near the end + * of the array. Mostly useful for checking for nullness. + */ + public Color[] getSolidColors() { return solids; } + + public BoxedFlob(int x, int y, int d, int w, int h, + ZZCell c) { + super(x, y, d, w, h, c); + } +} + + diff --git a/Java/flob/CellBgFlob.java b/Java/flob/CellBgFlob.java new file mode 100644 index 0000000..e52d533 --- /dev/null +++ b/Java/flob/CellBgFlob.java @@ -0,0 +1,118 @@ +/* +CellBgFlob.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A flob for the cell background. + * Draws a filled (possibly with several colors) background rectangle, + * surrounded by a rectangle of the current foreground color. + */ + +public class CellBgFlob extends Flob implements Colorer { +public static final String rcsid = "$Id: CellBgFlob.java,v 1.16 2001/02/26 18:03:29 raulir Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + boolean drawBorder = true; + + int nsolids = 0; + Color[] solids; + protected Color bg = Color.white; + + public Object hit(int x0, int y0) { + if( x0 >= x && y0 >= y && x0 < x+w && y0 < y+h ) + return c; + return null; + } + + public void setBg(Color c){ if( c != null ) bg = c; } + + /** Override this in subclasses to render something inside the cell. + */ + protected void renderContent(Graphics g, int mx, int my, int mw, int mh) { + } + + public void render(Graphics g, int mx, int my, int md, int mw, int mh) { + + // p("ZZCC1 render: "+g+" "+mx+" "+my+" "+mw+" "+mh); + Color oldfg = g.getColor(); + Shape oldclip = g.getClip(); + + // XXX save font? + + g.clipRect(mx, my, mw, mh); + + if(solids != null) { + for(int i=0; i= 14) { + g.drawRect(mx+1, my+1, mw-3, mh-3); + } + } + g.setClip(oldclip); + } + + /** Adds one more solid color to be drawn inside + * the cell. + */ + public boolean addColor(Color c) { + if(solids == null || nsolids >= solids.length) { + Color[] n= new Color[nsolids + 10]; + if(solids != null) System.arraycopy(solids, 0, n, 0, nsolids); + solids = n; + } + solids[nsolids++] = c; + return false; + } + /** The currently put solid colors. + * null = none. There may be null references near the end + * of the array. Mostly useful for checking for nullness. + */ + public Color[] getSolidColors() { return solids; } + + public CellBgFlob(int x, int y, int d, int w, int h, + ZZCell c) { + super(x, y, d, w, h, c); + } +} + + diff --git a/Java/flob/CellFlob1.java b/Java/flob/CellFlob1.java new file mode 100644 index 0000000..531e1a7 --- /dev/null +++ b/Java/flob/CellFlob1.java @@ -0,0 +1,105 @@ +/* +CellFlob1.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +public class CellFlob1 extends BoxedFlob { +public static final String rcsid = "$Id: CellFlob1.java,v 1.16 2001/03/18 17:50:16 bfallenstein Exp $"; + public static final boolean dbg = true; + + String s; + Font f; + // XXX Should this *really* need to be stored here? + FontMetrics fm; + + /** Font height. */ + int fh; + int fasc; + /** String width. */ + int sw; + + ZZCell strCell; + + int xoffs = 0; // Previously, these margins where three, but at the moment + int yoffs = 0; // margins are cared for by the BoxTypes + + static public final Dimension getSize(FontMetrics fm, String str, + int xoffs, int yoffs) { + int w = fm.stringWidth(str) + xoffs * 2 + 2; + int h = fm.getHeight() + 2*yoffs; + if(w < h) w = h; + return new Dimension( w, h ); + } + + public int getStrX(int ind) { + if(fm == null) throw new Error("No fontmetrics"); + if(ind > s.length()) { + // XXX What to do? + return x + xoffs + fm.stringWidth(s); + } + return x + xoffs + fm.stringWidth(s.substring(0, ind)) ; + } + + public void render(Graphics g, int mx, int my, int md, int mw, int mh) { + Shape oldClip = g.getClip(); + g.clipRect(mx, my, mw, mh); + int ty = my + (mh-fh)/2 + fasc; + g.setFont(f); + g.drawString(s, mx+xoffs, ty); + g.setClip(oldClip); + } + + public CellFlob1(int x, int y, int d, int w, int h, + ZZCell c, ZZCell strCell, String s, + Font f, FontMetrics fm) { + super(x, y, d, w, h, c); + + // Not true, since c can be the flob cell and d the referring + // cell. + // this.s = c.getText(); + + this.s = (s==null? "" : s); + this.strCell = strCell; + + this.f = f; + this.fm = fm; + + this.fh = fm.getAscent()+fm.getDescent(); + this.fasc = fm.getAscent()+fm.getLeading(); + this.sw = fm.stringWidth(this.s); + } + + public Object hit(int x0, int y0) { + if(!insideRect(x0, y0)) return null; + // Search for the right position in the string. + // We return a virtual cursor. + int ind = ZZUtil.findStringHit(s, x0-x-xoffs, fm); + + return new ZZCursorVirtual(strCell, ind); + } + +} + diff --git a/Java/flob/CellFlobFactory1.zob b/Java/flob/CellFlobFactory1.zob new file mode 100644 index 0000000..a52648a --- /dev/null +++ b/Java/flob/CellFlobFactory1.zob @@ -0,0 +1,205 @@ +/* +RasterFactory1.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A simple cell factory that gives the cells as one-line strings. + * Variable length is possible. + */ + +public class CellFlobFactory1 implements FlobFactory, ZOb { +public static final String rcsid = "$Id$"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + STRUCTPARAMS { + + /** The string to use to get the default cell width. */ + String widthstr + = "0000000000"; + + /** The default background color. + * XXX Currently, because of color mixing, the foreground + * comes from FlobSet. This should maybe change - check later. + */ + Color bg + = Color.white; + + /** The font for the default enlargement. */ + ScalableFont font + = new ScalableFont("SansSerif", Font.PLAIN, 12); + + /** Whether the font changes size with the enlargement. */ + boolean zoomfont + = true; + + /** Whether the font can get bigger than the default font. + * Ignored (or rather, doesn't have any effect) when zoomfont is false. + */ + boolean enlargefont + = true; + + /** The x and y margins + */ + int[] margins + = new int[] {2, 1}; + + /** Whether to produce BallCells instead? + */ + boolean ball + = false; + } + +/* + RasterCellFactory1(Component c) { + comp = c; + } +*/ + + protected Font fon(int scale) { return font.getFont(scale); } + protected FontMetrics fonmet(int scale) { + return font.getFontMetrics(scale); + } + protected int getScale(float fract) { return getScale(fract,false); } + protected int getScale(float fract,boolean real) { + if(!enlargefont && !real && fract>=1.0) return 1000; + return (int)(fract*1000); + } + + public Dimension getSize(ZZCell c, float fract) { + String str = widthstr; + if(c != null) str = c.getText(); + if(str == null) str = ""; + FontMetrics fm = fonmet(getScale(fract,true)); + if(ball) + return BallCell.getSize(fm, str, margins[0], margins[1]); + else + return CellFlob1.getSize(fm, str, margins[0], margins[1]); + } + + public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int d, int w, int h) { + int scale = getScale(fract); + Font f = fon(scale); + FontMetrics fm = fonmet(scale); + if(ball) { + BallCell cf = new BallCell(x, y, d, w, h, handleCell, c, + c.getText(), f, fm, into); + cf.xoffs = margins[0]; + cf.yoffs = margins[1]; + addSolidColors(into, cf, cf); + into.add(cf); + return cf; + } else { + CellFlob1 cf = new CellFlob1(x, y, d, w, h, handleCell, c, + c.getText(), f, fm); + cf.bg = bg; + cf.xoffs = margins[0]; + cf.yoffs = margins[1]; + addSolidColors(into, cf, cf); + into.add(cf); + return cf; + } + } + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract) { + Dimension d = getSize(c, fract); + return makeFlob(into, c, handleCell, fract, + (int)(x-xfract*d.width), + (int)(y-yfract*d.height), + depth, d.width, d.height); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d) { + if(d == null) d = getSize(c, fract); + int x, y; + if(ball) { + x = p.x - d.height/2; y = p.y - d.height/2; + } else { + x = p.x - d.width/2; y = p.y - d.height/2; + } + if(xalign < 0) x = p.x; + if(xalign > 0) x = p.x - d.width; + if(yalign < 0) y = p.y; + if(yalign > 0) y = p.y - d.height; + p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign); + return makeFlob(into, c, handleCell, fract, x, y, + depth, d.width, d.height); + } + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) { + return centerFlob(into, c, handleCell, fract, p, xalign, yalign, + depth, null); + } + + /** A routine to add solid background colors according to scheme 1. + * No better place to put it right now, but this routine can be + * called from anywhere to color the background of a cellbgflob + * as requested. + * Also adds line cursors, if any. + */ + static public void addSolidColors(FlobSet into, Flob f, Colorer col) { + // Special case check: Is this a cursor or a cursor's clone? + ZZCell orig = f.c.h("d.clone", -1); + if(orig.h("d.cursor-list", -1).s("d.cursor", -1) + != null) { + col.addColor(ZZCursorReal.getColorOrWhite(orig)); + return; // XXX should draw line cursors! + } + + Enumeration e = ZZCursorReal.getPointers(f.c); + while(e.hasMoreElements()) { + ZZCell cu = (ZZCell)e.nextElement(); + Color color = ZZCursorReal.getColor(cu); + if(color != null) if(col.addColor(color)) return; + if(!(f instanceof CellFlob1)) continue; + int offs = ZZCursorReal.getOffs(cu); + if(offs == ZZCursor.NO_OFFSET) continue; + int x = ((CellFlob1)f).getStrX(offs); + into.add(new LineDecor(x, f.y, x, f.y+f.h, + Color.black, f.d)); + } + + // XXX Does not check whose mark it is - should! + if(f.c.s("d.mark-set", 1)!=null) + if(col.addColor(Color.red)) return; + + if(f.c.s("d.clone", -1) != null) + if(col.addColor(Color.yellow)) return; + else if(f.c.s("d.clone", 1) != null) + if(col.addColor(new Color(255, 255, 192))) return; + + } + +} + + +// vim: set syntax=java : diff --git a/Java/flob/CellFlobFactory2.zob b/Java/flob/CellFlobFactory2.zob new file mode 100644 index 0000000..7c6fd82 --- /dev/null +++ b/Java/flob/CellFlobFactory2.zob @@ -0,0 +1,207 @@ +/* +RasterFactory2.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, multiline by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A simple cell factory that gives the cells as one-line strings. + * Variable length is possible. + * XXX This class is a bad copy of RasterCellFactory 1. + * Inheritance should be rather used, but doesn't work yet with ZObs. + */ + +public class CellFlobFactory2 implements FlobFactory, ZOb { +public static final String rcsid = "$Id$"; + public static boolean dbg = false; + private static final void p(String s) { if(dbg) System.out.println(s); } + private static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + + /** The string to use to get the default cell width. */ + String widthstr + = "0000000000"; + + /** The default background color. + * XXX Currently, because of color mixing, the foreground + * comes from FlobSet. This should maybe change - check later. + */ + Color bg + = Color.white; + + /** The font for the default enlargement. */ + ScalableFont font + = new ScalableFont("SansSerif", Font.PLAIN, 12); + + /** Whether the font changes size with the enlargement. */ + boolean zoomfont + = true; + + /** Whether the font can get bigger than the default font. + * Ignored (or rather, doesn't have any effect) when zoomfont is false. + */ + boolean enlargefont + = true; + + /** The x and y margins + */ + int[] margins + = new int[] {3, 2}; + + ZOb ftextlayouter + = new FTextLayouter(); + + } + + protected Font fon(int scale) { return font.getFont(scale); } + protected FontMetrics fonmet(int scale) { + return font.getFontMetrics(scale); + } + protected int getScale(float fract) { return getScale(fract, false); } + protected int getScale(float fract, boolean real) { + if(!enlargefont && !real && fract>=1.0) return 1000; + return (int)(fract*1000); + } + + public Dimension getSize(ZZCell c, float fract) { + String str = widthstr; + if(c != null) str = c.getText(); + if(str == null) str = ""; + FontMetrics fm = fonmet(getScale(fract, true)); + return CellFlob1.getSize(fm, str, margins[0]*2, margins[1]*2); + } + + public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, int x, int y, int d, int w, int h) { + int scale = getScale(fract); + Font f = fon(scale); + FontMetrics fm = fonmet(scale); + CellBgFlob cf = new CellBgFlob(x, y, d, w, h, c); + Point p = cf.getPoint(1, 1); + p = cf.getPoint(-1, -1); + cf.bg = bg; + int xm = margins[0], ym = margins[1]; + addSolidColors(into, cf); + + FText ftxt = new FText(new FText.Part[] { + new FText.CellPart(c, 0, -1, f, fm, null, null) + }); + Rectangle rect = new Rectangle(x+xm, y+ym, w-xm-xm, h-ym-ym); + +// XXX -- make this work! (shall place cursor in middle if text too long) +// int offs = -1; +// for(Enumeration e=ZZCursorReal.getPointers(c); e.hasMoreElements();) { +// int offs0 = ZZCursorReal.getOffs((ZZCell)e.nextElement()); +// if(offs0 != ZZCursorReal.NO_OFFSET) { offs = offs0; break; } +// } + + FTextLayouter ftl = (FTextLayouter)ftextlayouter; + ftl.firstCap = false; +// if(offs < 0) + ftl.place(into, ftxt, rect, d, 1, rect.y+1, 0, true, cf); +// else +// ftl.place(into, ftxt, rect, d, 0, +// rect.y+rect.height/2-fm.getHeight()/2, offs, true, cf); + + into.add(cf); + return cf; + } + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract) { + Dimension d = getSize(c, fract); + return makeFlob(into, c, handleCell, fract, + (int)(x-xfract*d.width), + (int)(y-yfract*d.height), + depth, d.width, d.height); + + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d) { + if(d == null) d = getSize(c, fract); + int x, y; + x = p.x - d.width/2; y = p.y - d.height/2; + if(xalign < 0) x = p.x - d.width; + if(xalign > 0) x = p.x; + if(yalign < 0) y = p.y - d.height; + if(yalign > 0) y = p.y; + return makeFlob(into, c, handleCell, fract, x, y, + depth, d.width, d.height); + } + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) { + return centerFlob(into, c, handleCell, fract, p, xalign, yalign, + depth, null); + } + + /** A routine to add solid background colors according to scheme 1. + * No better place to put it right now, but this routine can be + * called from anywhere to color the background of a cellbgflob + * as requested. + * Also adds line cursors, if any. + */ + static public void addSolidColors(FlobSet into, CellBgFlob f) { + // Special case check: Is this a cursor or a cursor's clone? + ZZCell orig = f.c.h("d.clone", -1); + if(orig.h("d.cursor-list", -1).s("d.cursor", -1) + != null) { + f.addColor(ZZCursorReal.getColorOrWhite(orig)); + return; // XXX should draw line cursors! + } + + ZZCell cu = f.c.s("d.cursor", 1); + + while(cu != null) { + Color color = ZZCursorReal.getColor(cu); + if(color != null) f.addColor(color); +// String txt = cu.getText(); +// if(txt != null && !txt.equals("") && f instanceof CellBgFlob) { +// try { +// int ind = Integer.parseInt(txt); +// int x = ((CellBgFlob)f).getStrX(ind); +// into.add(new LineDecor(x, f.y, x, f.y+f.h, +// Color.black, f.d)); +// } catch(NumberFormatException e) { +// } +// } + cu = cu.s("d.cursor-list", 1); + } + // XXX Does not check whose mark it is - should! + if(f.c.s("d.mark-set", 1)!=null) + f.addColor(Color.red); + + if(f.c.s("d.clone", -1) != null) + f.addColor(Color.yellow); + else if(f.c.s("d.clone", 1) != null) + f.addColor(new Color(255, 255, 192)); + + } + +} + + +// vim: set syntax=java : diff --git a/Java/flob/Colorer.java b/Java/flob/Colorer.java new file mode 100644 index 0000000..166447d --- /dev/null +++ b/Java/flob/Colorer.java @@ -0,0 +1,41 @@ +/* +Colorer.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** An interface for coloring cell background -like things. + * The information about how many colors are appropriate should + * move separately from this. + */ + +public interface Colorer { +String rcsid = "$Id: Colorer.java,v 1.1 2000/10/26 18:15:05 tjl Exp $"; + /** Add the given color to the set of colors to be shown in the background, + * or whatever. + * It is assumed that the colors come more significant first, so that + * Colorers are free to take any number of the first ones and ignore + * the rest. + * @return Whether the rest of the colors will be ignored. + */ + boolean addColor(Color c); +} diff --git a/Java/flob/CombinedView.zob b/Java/flob/CombinedView.zob new file mode 100644 index 0000000..fe40934 --- /dev/null +++ b/Java/flob/CombinedView.zob @@ -0,0 +1,58 @@ +/* +CombinedView.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; + +/** A view that shows all views of the accursed cell next to each other. + */ + +public class CombinedView implements FlobView, ZOb { +public static final String rcsid = "$Id: CombinedView.zob,v 1.6 2000/12/31 15:15:50 bfallenstein Exp $"; + /** Should we print out debugging info? */ + public static boolean dbg = false; + static final void p(String s) { if(dbg) pa(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS {} + + public void raster(FlobSet into, FlobFactory fact, + ZZCell win, String[] dims, ZZCell accursed) { + ZZCell[] apps = ApplitudeMgr.getApplitudes(accursed); + if(apps.length == 0) + apps = new ZZCell[] { ApplitudeMgr.getFallback(win.getSpace()) }; + int n = apps.length; + + ZZCell pref = ApplitudeMgr.getWindowApp(win); + Dimension size = new Dimension(into.getSize()); + if(pref != null) + fact.centerFlob(into, pref, pref, (float)1.5, + new Point(size.width, size.height), 1, 1, 1); + size.width = size.width / n; + + for(int i=0; i-" + + conns[i].c2.getID());*/ + + Vector dims = new Vector(); // Dims to be drawn + Vector pos = new Vector(); // Cells to positive directions to be drawn + Vector neg = new Vector(); // Cells to negative directions to be drawn + + ZZCell dim, pc, nc; + dim=stdim; + do { // Go through the DimList starting from the x-axis dimension + String cdim = dim.getText(); + p("Found dim: "+cdim); + pc = accursed.s(cdim, 1); + nc = accursed.s(cdim, -1); + if(nc != null || pc != null) { + dims.addElement(cdim); + pos.addElement(pc); + neg.addElement(nc); + } + dim = dim.s("d.2", 1); + } while(dim != stdim); // Do until loop closes + + int numdirs = pos.size()+neg.size(); // Number of cells and thus sectors + if(numdirs == 0) + return; // No cells to draw + double angle = 2 * Math.PI / (numdirs); + int l = (int) ((d.height < d.width ? d.height : d.width) / 2 * 0.5); + + fact.makeFlob(into, accursed, accursed, 1, + (d.width-cw) / 2, (d.height-ch) / 2, 1, cw, ch); + + int i = 0; + LineDecor.Builder nldb = new LineDecor.Builder(into, Color.black); + LineDecor.Builder pldb = new LineDecor.Builder(into, Color.red); + nldb.startl(numdirs/2*4, 12); + pldb.startl(numdirs/2*4, 12); + + double a = (double)-2/3*Math.PI; // Begin placing positive cells top left + while (i < numdirs/2) { + int dx = x(a, l); + int dy = y(a, l); + + if(pos.elementAt(i)!=null) { + fact.makeFlob(into, (ZZCell)pos.elementAt(i), (ZZCell)pos.elementAt(i), + (float) 0.7, + midx + dx-cw/2, midy + dy-ch/2, + 1, cw, ch); + pldb.l(midx, midy, midx + dx, midy + dy); + into.add(new TextDecor( + midx+dx+cw/2-dfm.stringWidth("+"+(String)dims.elementAt(i)), + midy+dy-ch/2, "+"+(String)dims.elementAt(i), Color.red, dfont)); + } + if(neg.elementAt(i)!=null) { + fact.makeFlob(into, (ZZCell)neg.elementAt(i), (ZZCell)neg.elementAt(i), + (float) 0.7, + midx -dx -cw/2, midy -dy -ch/2, + 1, cw, ch); + nldb.l(midx, midy, midx -dx, midy -dy); + into.add(new TextDecor( + midx-dx-cw/2, midy-dy+ch/2+dfonth, + "-"+(String)dims.elementAt(i), Color.black, dfont)); + } + + i++; + a += angle; // Rotate clockwise + } + nldb.endl(); + pldb.endl(); + } + + protected int x(double angle, int length) { + return (int) (Math.cos(angle) * length); + } + + protected int y(double angle, int length) { + return (int) (Math.sin(angle) * length); + } +} + +// vim: set syntax=java : diff --git a/Java/flob/ConnectionLineDecor.java b/Java/flob/ConnectionLineDecor.java new file mode 100644 index 0000000..a1ac9f5 --- /dev/null +++ b/Java/flob/ConnectionLineDecor.java @@ -0,0 +1,174 @@ +/* +ConnectionLineDecor.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A decoration of lines connecting flobs to each other. + * Interpolation is done by this class. The coordinates are + * given as points inside the flob's rectangle. + */ + +public class ConnectionLineDecor extends Flob { +public static final String rcsid = "$Id: ConnectionLineDecor.java,v 1.5 2000/09/19 10:31:59 ajk Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + /** A class that incrementally builds these. + */ + static public class Builder { + FlobSet into; + int curp; int np; + Flob[] flobs; + int[] p; + Color col; + int d; + public Builder(FlobSet into, Color col) { + this.into = into; + this.col = col; + } + public final void startl(int n, int d) { + if(curp != 0) endl(); + this.d = d; + curp = 0; + np = n; + p = null; + flobs = null; + } + public final void l(Flob f0, int x0, int y0, Flob f1, int x1, int y1) { + if(p==null) { + p = new int[np * 4]; + flobs = new Flob[np * 2]; + } else if(curp >= np) { + endl(); + p = new int[np * 4]; + flobs = new Flob[np * 2]; + curp = 0; + } + flobs[curp*2 + 0] = f0; + flobs[curp*2 + 1] = f1; + p[curp*4 + 0] = x0; + p[curp*4 + 1] = y0; + p[curp*4 + 2] = x1; + p[curp*4 + 3] = y1; + curp ++; + } + public void endl() { + if(p==null) return; + into.add(new ConnectionLineDecor(flobs, p, curp, col, d)); + p = null; flobs = null; curp = 0; + } + } + + Color color; + int n; + Flob[] flobs; + int[] coords; // 256th parts + + public ConnectionLineDecor(Flob[] flobs, int[] coords, int n, int d) { + this(flobs, coords, n, null, d); + } + + /** Usual constructor. + * @param coords The coordinates for the lines, given as + * quadruplets x1, y1, x2, y2. + */ + public ConnectionLineDecor(Flob[] flobs, int[] coords, int n, Color color, int d) { + // XXX Is size 0x0 right? + super(0, 0, d, 0, 0, null); + this.flobs = flobs; + this.coords = coords; + this.n = n; + this.color = color; + } + + public void render(Graphics g) { + Color old = null; + if(color != null) { + old = g.getColor(); + g.setColor(color); + } + g.setColor(Color.black); + p("Drawing flobconns"); + + for(int i=0; i p.length) + endl(); + if(p==null) + alloc(); + } + /** Allocate the arrays. */ + protected void alloc() { + p = new int[np]; + curp = 0; + nth = 0; + } + public void endl() { + if(p==null) return; + into.add(create()); + p = null; curp = 0; + } + abstract protected Renderable create(); + + } + + public CoordDecor(int[] coords, int n, int d) { + this.coords = coords; + this.n = n; + this.d = d; + if(coords != null && coords.length < n) + throw new Error("CoordDecor: less length than n!!!"); + } + + abstract public void render(Graphics g); + + public boolean translate(int x, int y) { + for(int i=0; i maxdepth) return; + + if (drawn.containsKey(centercell)) return; + + Vector pointers = new Vector(); + + { + Dimension s = fact.getSize(null, 1); + int width = (int) (s.width * sfactor); + int height = (int) (s.height * sfactor); + int x = centerpoint.x - width / 2; + int y = centerpoint.y - height / 2; + p("radius = " + radius + ", x = " + x + ", y = " + + y + ", width = " + width + ", height = " + + height + ", centercell = " + centercell); + Flob fl = fact.makeFlob(into, centercell, centercell, 1, + x, y, level, width, height); + drawn.put(centercell, centercell); + } + + for (Enumeration e = ZZCursorReal.getPointers(centercell); + e.hasMoreElements();) { + ZZCell c = (ZZCell) e.nextElement(); + pointers.addElement(c); + p("Found cursor " + c); + } + + int n = pointers.size(); + p("n = " + n); + + if (n == 0) return; + + int prad = (int) (pointerradius * radius); + + double baseangle = Math.PI / (n + 1); + + int newradius; + { + double a = prad - prad * Math.cos(baseangle); + double b = prad * Math.sin(baseangle); + newradius = (int) Math.sqrt(a * a + b * b); + p("a = " + a + ", b = " + b + ", newradius = " + newradius); + } + + for (int i = 0; i < n; i++) { + ZZCell c = (ZZCell) pointers.elementAt(i); + if (ZZCursorReal.get(c) != centercell) pa("WRONG CURSOR CELL FOUND!!!"); + double angle = (i + 1) * baseangle; + p("angle = " + angle + " rad, " + angle * 180 / Math.PI + " deg"); + int x = (int)(centerpoint.x + prad * Math.cos(angle)); + int y = (int)(centerpoint.y + prad * Math.sin(angle)); + drawPointerCells(into, fact, c, new Point(x, y), newradius, + level + 1, sfactor * sizefactor); + } + + + + } + + public void raster(final FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + ZZCell c = accursed; + Point pt = new Point(into.getSize().width / 2, + into.getSize().width / 2); + ZZCell ccand = ZZCursorReal.get(c); + if (ccand != null) { + c = ccand; + pt.y /= 2; + } + drawn = new Hashtable(); + drawPointerCells(into, fact, c, pt, + into.getSize().width, initdepth, 1); + + // Draw the cursor arrows + into.iterDepth(new FlobSet.DepthIter() { + public void act(Flob[] flobs, int start, int n) { + for(int i = start; i < start+n; i++) { + ZZCell pointer = flobs[i].c; + if (pointer == null) continue; + ZZCell pointee = ZZCursorReal.get(pointer); + if (pointee == null) continue; + p("pointer = " + pointer + ", pointee = " + pointee); + Flob from = flobs[i]; + Flob[] tos = into.findFlobs(null, pointee); + for (int j = 0; j < tos.length; j++) { + Flob to = (Flob) tos[j]; + int[] cs = new int[16]; + // we make the arrow body in two parts: + // one from head to arrow point and one + // from arrow point to tail + cs[0] = from.x + from.w / 2; + cs[1] = from.y; + cs[2] = to.x + to.w / 2; + cs[3] = to.y + to.h; + double or1 = (cs[0] + cs[2]) / 2; + double or2 = (cs[1] + cs[3]) / 2; + cs[6] = cs[2]; + cs[7] = cs[3]; + cs[2] = (int) (or1 + 0.5); + cs[3] = (int) (or2 + 0.5); + cs[4] = cs[2]; + cs[5] = cs[3]; + double v1 = cs[0] - cs[2]; + double v2 = cs[1] - cs[3]; + double vlen = Math.sqrt(v1*v1 + v2*v2); + v1 = v1 / vlen; + v2 = v2 / vlen; + cs[8] = (int) (or1 + 0.5); + cs[9] = (int) (or2 + 0.5); + cs[10] = (int) (v1 * a00 + v2 * a01 + or1 + 0.5); + cs[11] = (int) (v1 * a10 + v2 * a11 + or2 + 0.5); + cs[12] = (int) (or1 + 0.5); + cs[13] = (int) (or2 + 0.5); + cs[14] = (int) (v1 * b00 + v2 * b01 + or1 + 0.5); + cs[15] = (int) (v1 * b10 + v2 * b11 + or2 + 0.5); + into.add(new LineDecor(cs, cs.length, + linecolor, + (from.d + to.d) / 2)); + } + + } + } + }, true); + + + } + + +} + + + diff --git a/Java/flob/FTextCellView.zob b/Java/flob/FTextCellView.zob new file mode 100644 index 0000000..8db134f --- /dev/null +++ b/Java/flob/FTextCellView.zob @@ -0,0 +1,179 @@ +/* +FTextCellView.zob + * + * Copyright (c) 2001, Benja Fallenstein + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benja Fallenstein + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A cell view showing some FText. + * This class exists in order to make it easy to create cell views which + * just take an FText for a cell somehow and then render it on the screen. + * Subclasses have to implement getFText(ZZCell, int). Default: render the + * cell's content in the specified string. + *

    + * XXX Don't use scene flobs. Instead, just place the split cell flobs in the + * higher level flob set and create a BoxedFlob 'round them. + */ + +public class FTextCellView implements FlobFactory, ZOb { +public static final String rcsid = "$Id: FTextCellView.zob,v 1.4 2001/04/02 20:20:54 bfallenstein Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + // WHAT SUBCLASSES NEED TO OVERRIDE + + /** Get the FText for this cell at the given scale. + * scale == fract * 1000. + */ + protected FText getFText(ZZCell c, int scale) { + return new FText(new FText.Part[] { + new FText.CellPart(c, 0, -1, f(scale), fm(scale), null, null) + }); + } + + + + // IMPLEMENTATION + + /** Get the font for a given scale. */ + protected final Font f(int sc) { return font.getFont(sc); } + + /** Get the font metrics for a given scale. */ + protected final FontMetrics fm(int sc) { return font.getFontMetrics(sc); } + + STRUCTPARAMS { + /** The string to use to get the default cell width. */ + String widthstr + = "0000000000"; + + /** The default background color. + * XXX Currently, because of color mixing, the foreground + * comes from FlobSet. This should maybe change - check later. + */ + Color bg + = Color.white; + + /** The font for the default enlargement. */ + ScalableFont font + = new ScalableFont("SansSerif", Font.PLAIN, 12); + + ZOb ftextlayouter + = new FTextLayouter(false); + + /** The x and y margins + */ + int[] margins + = new int[] {2, 1}; + } + + protected int getScale(float fract) { + return (int)(fract*1000); + } + + public Dimension getSize(ZZCell c, float fract) { + if(c != null) { + FText ftxt = getFText(c.getRootclone(), getScale(fract)); + return new Dimension(FText.Part.width(ftxt.parts) + margins[0]*2, + FText.Part.height(ftxt.parts) + margins[1]*2); + } else { + String str = widthstr; + if(str == null) str = ""; + FontMetrics fm = fm(getScale(fract)); + return CellFlob1.getSize(fm, str, margins[0], margins[1]); + } + } + + public Flob getFlob(FlobSet into, ZZCell c, FText ftxt, + int x, int y, int d, int w, int h) { + int xm = margins[0], ym = margins[1]; + + BoxedFlob box = new BoxedFlob(x, y, d, w, h, c); + + CellFlobFactory1.addSolidColors(into, box, box); + + Rectangle rect = new Rectangle(x+xm, y+ym, w-xm, h-ym); + ((FTextLayouter)ftextlayouter).place(into, ftxt, rect, d, 1, y+ym, 0, + true, box); + + // Add the box last, so that it is shown under the text. + into.add(box); + return box; + } + + public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, int x, int y, int d, int w, int h) { + FText ftxt = getFText(c.getRootclone(), getScale(fract)); + return getFlob(into, c, ftxt, x, y, d, w, h); + } + + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract) { + FText ftxt = getFText(c.getRootclone(), getScale(fract)); + int w = FText.Part.width(ftxt.parts) + margins[0]*2; + int h = FText.Part.height(ftxt.parts) + margins[1]*2; + return getFlob(into, c, ftxt, + (int)(x-xfract*w), + (int)(y-yfract*h), + depth, w, h); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d) { + if(d == null) return centerFlob(into, c, handleCell, fract, p, xalign, + yalign, depth); + int x, y; + x = p.x - d.width/2; y = p.y - d.height/2; + + if(xalign < 0) x = p.x; + if(xalign > 0) x = p.x - d.width; + if(yalign < 0) y = p.y; + if(yalign > 0) y = p.y - d.height; + p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign); + return makeFlob(into, c, handleCell, fract, x, y, + depth, d.width, d.height); + } + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) { + int x, y; + + FText ftxt = getFText(c.getRootclone(), getScale(fract)); + int w = FText.Part.width(ftxt.parts) + margins[0]*2; + int h = FText.Part.height(ftxt.parts) + margins[1]*2; + + x = p.x - w/2; y = p.y - h/2; + if(xalign < 0) x = p.x; + if(xalign > 0) x = p.x - w; + if(yalign < 0) y = p.y; + if(yalign > 0) y = p.y - h; + p("centerFlob "+p+" at "+x+" "+y+" "+w+" "+h+" align "+xalign+" "+yalign); + + return getFlob(into, c, ftxt, x, y, depth, w, h); + } +} + +// vim: set syntax=java : diff --git a/Java/flob/FTextLayouter.zob b/Java/flob/FTextLayouter.zob new file mode 100644 index 0000000..f19d335 --- /dev/null +++ b/Java/flob/FTextLayouter.zob @@ -0,0 +1,253 @@ +/* +FTextLayouter.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A layouter for flowing formatted text in a fixed-width rectangle. + * @see FText + */ + +public class FTextLayouter implements ZOb { +public static final String rcsid = "$Id: FTextLayouter.zob,v 1.10 2001/03/30 16:19:37 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + public FTextLayouter() {} + public FTextLayouter(boolean firstCap) { this.firstCap = firstCap; } + + STRUCTPARAMS { + /** Capitalize any letter after two spaces. + * This allows simple rearrangement of text without having + * to think about capitalization at all times by ending + * each sentence with the period/question/... and two spaces. + * XXX Maybe this shouldn't be here after all - maybe + * separate FText.Part firstcap completely from rendering + * to a separate call?? + */ + boolean firstCap + = true; + + } + + /** (Internal convenience) Place a number of lines from an array, + * given first and last line. + */ + void placeLines(FlobSet into, + FText.Part[][] lines, + int[] heights, + Rectangle rect, + int first, + int last, + int depth, + boolean cursors, + Flob fparent) { + int y = rect.y, maxx = rect.x + rect.width; + p("FTextLayouter placeLines first "+first+" last "+last+" length "+lines.length); + + Renderable prev = null; + for(int linenr=first; linenr<=last; linenr++) { + FText.Part[] line = lines[linenr]; + int x = rect.x; + y += heights[linenr]; + + for(int partnr = 0; partnr rect.x + rect.width) { + p("FTL clip: "+f.x+" "+f.w+" in "+rect.x+" "+rect.width+" at "+f.c); + f.w = rect.x + rect.width - f.x; + if(f instanceof SplitCellFlob1) + ((SplitCellFlob1)f).doClip = true; + } + if(f.w < 0) f.w = 0; + } + into.add(prev); + } + + x += w; + if(x > maxx) break; + } + } + } + + /** (Internal convenience) Find the correct span of lines to layout. + * Returns an array with two ints: the last line number and the height. + */ + int[] layout(FText.Part[][] lines, + int[] heights, + int start, + int dir, + int maxh) { + int height = 0, i = start; + for(; i>=0 && i maxh) return new int[] { i-dir, height }; + height += lineh; + } + return new int[] { i-dir, height }; + } + + + public Rectangle place(FlobSet into, FText txt, Rectangle rect, + int direction, int initY, + int middleoffs, + boolean cursors) { + return place(into, txt, rect, 100, + direction, initY, middleoffs, cursors, (Flob)null); + } + + /** To be deprecated -- DON'T USE! */ + public Rectangle place(FlobSet into, FText txt, Rectangle rect, + int direction, int initY, + int middleoffs, + boolean cursors, + boolean[] beginningSentence) { + return place(into, txt, rect, 100, + direction, initY, middleoffs, cursors, (Flob)null); + } + + /** To be deprecated -- DON'T USE! */ + public Rectangle place(FlobSet into, FText txt, Rectangle rect, + int depth, + int direction, int initY, + int middleoffs, + boolean cursors, + boolean[] beginningSentence) { + return place(into, txt, rect, depth, + direction, initY, middleoffs, cursors, (Flob)null); + } + + public Rectangle place(FlobSet into, FText txt, Rectangle rect, + int depth, + int direction, int initY, + int middleoffs, + boolean cursors) { + return place(into, txt, rect, depth, + direction, initY, middleoffs, cursors, (Flob)null); + } + + /** Place a piece of formatted text into a fixed-width rectangle. + * @param into The flobset to place the text into. + * @param txt The formatted text object + * @param rect The rectangle to fit things into. This is used for + * both stopping rendering at the upper and lower edges + * and for the margin widths. + * (XXX How to i18nize this for other directions?!?!) + * @param depth The depth at which to place the flobs. + * @param direction The direction we're moving. + * 0 = starting from the middle of a paragraph, + * 1 = down, -1 = up + * @param initY The y coordinate to place the middle/first/last line + * of text at, depending on direction. + * @param middleoffs If direction==0, the offset that should be at initY. + * @param cursors Whether to draw cursors. + * @param fparent The flob parent. + */ + public Rectangle place(FlobSet into, FText txt, Rectangle rect, + int depth, + int direction, int initY, + int middleoffs, + boolean cursors, + Flob fparent) { + if(firstCap) txt.capitalize(); + FText.Part[][] lines = txt.getLines(rect.width); + if(lines.length == 0) + return new Rectangle(rect.x, initY, rect.width, 0); + + /** The height of each line. */ + int[] heights = new int[lines.length]; + + /** The first and last lines to place. */ + int first, last; + + Rectangle res; + + if(direction < 0) { + last = lines.length-1; + int[] lay = layout(lines, heights, last, -1, + initY-rect.y); + + + first = lay[0]; last = lines.length-1; + res = new Rectangle(rect.x, initY-lay[1], rect.width, lay[1]); + } else if(direction > 0) { + first = 0; + int[] lay = layout(lines, heights, first, 1, + rect.y + rect.height - initY); + last = lay[0]; + res = new Rectangle(rect.x, initY, rect.width, lay[1]); + } else { + int middle = FText.findLine(lines, middleoffs); + // Make it the middle of the middle line. + initY -= FText.Part.height(lines[middle])/2; + + int[] lay1 = layout(lines, heights, middle-1, -1, + rect.y + rect.height - initY); + int[] lay2 = layout(lines, heights, middle, 1, initY-rect.y); + + first = lay1[0]; last = lay2[0]; + res = new Rectangle(rect.x, initY-lay1[1], rect.width, + lay1[1]+lay2[1]); + } + + placeLines(into, lines, heights, res, first, last, depth, + cursors, fparent); + return res; + } + + // XXX make more efficient: do cursor search only for parent sf + public static void addCurs(FlobSet into, SplitCellFlob1 sf) { + + Enumeration e = ZZCursorReal.getPointers(sf.getCell()); + while(e.hasMoreElements()) { + ZZCell c = (ZZCell)e.nextElement(); + + int ind = ZZCursorReal.getOffs(c); + if(ind == ZZCursorReal.NO_OFFSET) continue; + if(!(ind >= sf.start && ind <= sf.start + sf.n)) + continue; + int x = sf.getStrX(ind); + if(x >= 0 && into != null) + into.add(new LineDecor(x, sf.y, x, sf.y+sf.h, + Color.black, sf.d)); + } + } +} + +// vim: set syntax=java : diff --git a/Java/flob/Flob.java b/Java/flob/Flob.java new file mode 100644 index 0000000..f45030e --- /dev/null +++ b/Java/flob/Flob.java @@ -0,0 +1,202 @@ +/* +Flob.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** An abstract class to represent a flob shown on screen. + * Flobs are constant read-only objects like Strings. + *

    + * Flobs should be able to render themselves quickly for animations; + * caching relevant + * information in this structure is therefore a good idea. + *

    + * The minimal flob implementation simply implements the + * render(Graphics, int, int, int, int, int) method. + */ + +public abstract class Flob extends Renderable { +public static final String rcsid = "$Id: Flob.java,v 1.18 2001/03/17 23:08:23 bfallenstein Exp $"; + public int x, y, w, h; + + /** The identifier of the place this flob is. + * This is used to create a possibly hierarchical + * system so that animation doesn't confuse two + * instances of the same cell. + * deprecated Use setParent() / getParent(). + */ + public String flobPath = ""; + + /** The cell associated with this flob. + * This may be set to null for things that are - well - just + * things rendered. But those should be in a minority always. + */ + public ZZCell c; + + /** The flob we are interpolating with. + * Storing it here is a pure speed hack: in reality it'd belong in + * a hashtable somewhere. But this is crucial for the frame rate. + */ + protected Flob interpTo; + + /** The parent of this flob. + * Only flobs with no parents and flobs whose parents are interpolated + * to each other are interpolated to each other. + *

    + * set/get by setParent() / getParent() + */ + private Flob flobparent = null; + + /** The applitude that has placed this flob. + * When the views of different applitudes are combined, this field is set + * by the combining view. When a flob is clicked upon, the field is read, + * the applitude is made the window's prefered applitude, and the mouse + * binding is executed according to the bindings of that applitude. + */ + public ZZCell applitude = null; + + public void setParent(Flob p) { + flobparent = p; + flobPath = p.flobPath + "-" + p; + } + + public Flob getParent() { return flobparent; } + + /** Return true if a box should be drawn around this flob. + */ + public boolean needsBox() { return false; } + + public Flob(int x, int y, int d, int w, int h, ZZCell c) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.d = d; + this.c = c; + } + + /** Get a point aligned in a cell. + * getPoint(-1, 0) --> left/middle + * getPoint(1, 1) --> right/lower + * etc. -- middle means visual center (getCenter()). + */ + public Point getPoint(Point p, int xa, int ya) { + getCenter(p); + if(xa < 0) p.x = x; + if(xa > 0) p.x = x+w; + if(ya < 0) p.y = y; + if(ya > 0) p.y = y+h; + return p; + } + public Point getPoint(int xo, int yo) { + return getPoint(new Point(), xo, yo); + } + + /** Get the visual center of this flob. + */ + public Point getCenter(Point p) { + p.x = x+w/2; p.y = y+h/2; + return p; + } + + /** Get the visual center of this flob. + */ + public Point getCenter() { + return getCenter(new Point()); + } + + /** Render this flob at the given coordinates. + * Default: render nothing. + * You may override either this function or one or both of + * render(Graphics) and renderInterp(Graphics, float). + */ + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + } + + /** Render this flob. + * May be overridden; default implementation uses render(g, x, y, w, h, d); + */ + public void render(Graphics g) { + render(g, x, y, d, w, h); + } + /** Render an interpolated version of this flob. + * Default implementation uses render(g, x, y, w, h, d) with linearly + * interpolated coordinates. + */ + public void renderInterp(Graphics g, float fract) { + Flob r = interpTo; + if(r==null) return; + render(g, + (int)(x + fract*(r.x-x)), + (int)(y + fract*(r.y-y)), + (int)(d + fract*(r.d-d)), + (int)(w + fract*(r.w-w)), + (int)(h + fract*(r.h-h)) + ); + } + + /** If there is a XOR-cursor associated with this flob, + * render it. + * This can be made to e.g. follow the mouse cursor to + * show where the click would land. + * Default implementation: do nothing, return + *

     hit(x,y)!=null 
    + * @return Whether the coordinates hit this flob, i.e. + * whether the system should stop looking for the + * XOR curser. + */ + public boolean renderXOR(Graphics g, int x, int y) { + return hit(x,y) != null; + } + + /** Whether it would make visually sense to interpolate + * this flob. + * Default implementation: whether the sum of the squares of + * the differences of the coordinates and widths is more than 100. + * Not a terribly useful measure but good enough. + */ + public boolean isInterpUseful() { + Flob r = interpTo; + if(r==null) return false; + return (r.x - x) * (r.x - x) + + (r.y - y) * (r.y - y) + + (r.w - w) * (r.w - w) + + (r.h - h) * (r.h - h) > 100; + } + + + /** Returns an object telling what was hit. + * Default implementation: returns null. + */ + public Object hit(int x, int y) { return null; } + + /** A convenience routine to check whether a point + * is inside the defining rectangle. + * If the flob is (as many are) rectangular, this routine can + * be used to check the hit. + */ + public final boolean insideRect(int x0, int y0) { + return x0 >= x && y0 >= y && x0 < x+w && y0 < y+h; + } +} diff --git a/Java/flob/FlobDecorator.java b/Java/flob/FlobDecorator.java new file mode 100644 index 0000000..9533d6a --- /dev/null +++ b/Java/flob/FlobDecorator.java @@ -0,0 +1,39 @@ +/* +FlobDecorator.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** An interface for classes that decorate FlobSets by drawing connections + * or so. + */ + +public interface FlobDecorator { +String rcsid = "$Id: FlobDecorator.java,v 1.6 2000/10/26 18:09:29 tjl Exp $"; + /** Add Renderables or Flobs to the given flobset, + * based on the flobs already in there. + */ + void decorate(FlobSet f, String path, ZZCell view); +} diff --git a/Java/flob/FlobFactory.java b/Java/flob/FlobFactory.java new file mode 100644 index 0000000..c77f1db --- /dev/null +++ b/Java/flob/FlobFactory.java @@ -0,0 +1,89 @@ +/* +RasterFlobFactory.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** An interface to generate flobs to put in a raster. + * This is for abstracting out what the cells look like. + * The "CellViews" in ZZDefaultSpace corresponds to classes + * implementing this interface. + */ + +public interface FlobFactory { +String rcsid = "$Id$"; + /** Get the default dimensions for the given cell and fraction. + * @param c The cell. If null, the default dimensions overall are returned. + * @param fract The magnification fraction. + */ + Dimension getSize(ZZCell c, float fract); + + /** Create a 2-D flob. + * This call creates the flob and places it into the given FlobSet. + * @param c The cell for the flob + * @param handleCell The cell from which to show e.g. cursor. + * This mechanism may change. + */ + Flob makeFlob(FlobSet f, + ZZCell c, ZZCell handleCell, + float fract, int x, int y, int d, int w, int h); + + /** Place a flob. + * Here, the size can vary freely: the flob is placed so that + * the point (x,y) is at (xfract, yfract) in the unit coordinate + * system stretched to fit inside. E.g. if (xfract, yfract)==(0,1) + * then (x,y) will be the lower left corner. + * The reason for this call is that it may be almost twice as fast + * as doing getSize() and makeFlob() since both may have to do some + * of the same calculations (e.g. line breaking). + *

    + * This call should give the same results as + *

    +     *		Dimension d = getSize(c, fract);
    +     *		return makeFlob(c, fract, 
    +     *			(int)(x-xfract*d.width),
    +     *			(int)(y-yfract*d.height),
    +     *			depth, d.width, d.height);
    +     * 
    + */ + Flob placeFlob(FlobSet f, + ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract); + + + // should call centerFlob(..., null) + Flob centerFlob(FlobSet f, + ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth); + + // if d==null, use what getSize would return + Flob centerFlob(FlobSet f, + ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d); +} + + diff --git a/Java/flob/FlobSet.java b/Java/flob/FlobSet.java new file mode 100644 index 0000000..806e45e --- /dev/null +++ b/Java/flob/FlobSet.java @@ -0,0 +1,521 @@ +/* +FlobSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A set of flobs, i.e.things that are rendered to screen associated + * with cells. + * Flobs are stored with depths, which are stably sorted in the end + * so that the flobs placed later are on top. + */ + +public class FlobSet implements ZZScene { +public static final String rcsid = "$Id: FlobSet.java,v 1.41.2.1 2002/03/07 21:02:41 bfallenstein Exp $"; + + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + Dimension size; + public Dimension getSize() { + return size; + } + Color fg, bg; + Component cpt; + + public SceneFlob sflob = null; + public BoxType box = new SimpleBoxType(); + + public FlobSet(Dimension size, Color foreground, Color background, + Component cpt) { + this.size = size; + this.bg = background; + this.fg = foreground; + this.cpt = cpt; + } + public Component getComponent() { return cpt; } + public Color getForeground() { return fg; } + public Color getBackground() { return bg; } + + + private Hashtable c2ph; + private Hashtable nph; // Hashtable for flobs w/o parents + + private final Hashtable getPH(Flob parent) { + if(parent == null) + return nph; + Hashtable res = (Hashtable)c2ph.get(parent); + if(res == null) + c2ph.put(parent, res=new Hashtable()); + return res; + } + + private int nflobs; + private Flob[] flobs = new Flob[30]; + boolean fsorted = false; + boolean ftagged = false; + + + private int nrend; + /** Decorations. + */ + private Renderable[] rends = new Renderable[10]; + boolean rsorted = false; + + private int maxdepth = 0; + + public void add(Renderable r) { + // Check: if it happens to be a flob, then put + // it as a flob. + if(r instanceof Flob) { + add((Flob)r); + return; + } + + if(r.d > maxdepth) maxdepth = r.d; + if(nrend >= rends.length) { + Renderable[] n = new Renderable[nrend + 50]; + System.arraycopy(rends, 0, n, 0, nrend); + rends = n; + } + rends[nrend++] = r; + rsorted = false; + } + + /** Add a flob into the flobset. + * Note that flobPath might not be set yet. + * It is therefore used only when the flobs are being sorted. + */ + public void add(Flob f) { + // p("AddFlob "+f.x+" "+f.y+" "+f.w+" "+f.h+" "+f.d); + if(f.d <= 0) + throw new ZZError("Negative or zero depth for flob!"); + if(f.d > maxdepth) maxdepth = f.d; + // if(f.c != null) + // getPH(f.flobPath).put(f.c, f); + if(nflobs >= flobs.length) { + Flob[] n = new Flob[nflobs + 100]; + System.arraycopy(flobs, 0, n, 0, nflobs); + flobs = n; + } + flobs[nflobs++] = f; + fsorted = false; + ftagged = false; + if(sflob != null && f instanceof SceneFlob) + ((SceneFlob)f).parent = sflob; + } + + public final void tag() { + if(ftagged) return; + c2ph = new Hashtable(); nph = new Hashtable(); + for(int i=0; i maxdepth) + throw new ZZError("Too strange. "+depth+" "+maxdepth); + int fract = (256*(depth-1)) / (maxdepth + maxdepth / 10); + Color ncol = ZZUtil.mix(fg, bg, fract); + g.setColor(ncol); + // p("Color: "+fract+" "+d+" "+maxdepth+" "+ncol); + } + + public void render(Graphics g) { + render(g, g); + } + public void render(Graphics g, Graphics orig) { + + // ZZDrawing.instance.setAlpha(g, (float)0.5); + ZZDrawing.instance.setDefaults(g); + ZZDrawing.instance.setQuality(g); + + int f=nflobs-1; + int r=nrend-1; + int oldd = -1; + sort(); + // p("StartColors"); + while(f >= 0 || r >= 0) { + // Stagger the two arrays. Always render decorations of the same + // depth last + while(f >= 0 && + ( r < 0 || rends[r].d <= flobs[f].d)) { + if(flobs[f].d != oldd) + depthColor(g, oldd = flobs[f].d); + if(!flobs[f].needsBox()) + flobs[f--].render(g, orig); + else { + Flob fl = flobs[f--]; + box.renderBg(g, fl); + fl.render(g, orig); + box.renderFrame(g, fl); + } + } + while(r >= 0 && + ( f < 0 || rends[r].d > flobs[f].d)) { + if(rends[r].d != oldd) + depthColor(g, oldd = rends[r].d); + rends[r--].render(g, orig); + } + } + renderDC(g); + } + + FlobSet interpPrepared = null; + public void renderInterp(Graphics g, ZZScene other0, + float fract) { + + ZZDrawing.instance.setDefaults(g); + + sort(); + FlobSet other = (FlobSet)other0; + if(interpPrepared != other) { + prepareInterp(other); + } + renderInterp(g, fract); + } + + public void renderInterp(Graphics g, float fract) { + int oldd = -1; + for(int i=nflobs-1; i>=0; i--) { + if(flobs[i].d != oldd) + depthColor(g, oldd = flobs[i].d); + if(flobs[i].interpTo == null || !flobs[i].needsBox()) + flobs[i].renderInterp(g, fract); + else { + // XXX the interpolation path isn't necessarily linear! + box.renderBg(g, flobs[i], fract); + flobs[i].renderInterp(g, fract); + box.renderFrame(g, flobs[i], fract); + } + } + } + + public boolean isInterpUseful(ZZScene other0) { + FlobSet other = (FlobSet)other0; + return prepareInterp(other); + } + + /** Find flobs for this parent and cell. + * @returns null if no flobs are found (empty array would be inefficient) + */ + public Flob[] findFlobs(Flob parent, ZZCell c) { + tag(); + Hashtable hash = getPH(parent); + Object o = hash.get(c); + if(o == null) return null; + else if(o instanceof Flob) return new Flob[] { (Flob)o }; + else if(o instanceof Flob[]) return (Flob[])o; + + // Now, we have a Vector. Convert to array. + Vector v = (Vector)o; + Flob[] res = new Flob[v.size()]; + for(int i=0; i=0; i--) { + if(flat && flobs[i] instanceof SceneFlob) { + di.act(flobs, i+1, cur-i, sflob); + ((SceneFlob)flobs[i]).getFlobSet().iterDepth(di, true, true); + cur = i; curd = flobs[i].d; + } if(curd != flobs[i].d) { + di.act(flobs, i+1, cur-i, sflob); + cur = i; + curd = flobs[i].d; + } + } + di.act(flobs, 0, cur+1); + } + } + + /** Iterate a routine over blocks of same-depth flobs. + * Does not include flobs inside SceneFlobs. + */ + public void iterDepth(DepthIter di, boolean frontFirst) { + iterDepth(di, frontFirst, false); + } + + DragCursor dc; int dcx, dcy; + public void setDragCursor(DragCursor dc, int x, int y) { + this.dc = dc; this.dcx = x; this.dcy = y; + } + public interface DragCursor { + boolean accept(Object o); + } + + /** Render the current dragCursor. + */ + private void renderDC(Graphics g) { + if(dc == null) return; + Flob[] which = new Flob[1]; + Object co = getObjectAt(dcx, dcy, which); + if(co == null) return; + if(!dc.accept(co)) return; + which[0].renderXOR(g, dcx, dcy); + } + + public int fetch(FlobSet from, int x, int y, int d) { + return fetch(from, x, y, d, null); + } + + /** Fetch the contents of another FlobSet and translate coordinates. + * Takes all flobs and rends, adds x, y and do to their coordinates, + * and puts them in this set. This is used to combine views. + * @param Whenever a flob's applitude field contains null, it is set + * to this value (which may be null in itself). + * @returns The highest depth used (or d, if there weren't any flobs). + */ + public int fetch(FlobSet from, int x, int y, int d, ZZCell applitude) { + int res = d; + for(int i=0; i res) res = f.d; + if(f.applitude == null) f.applitude = applitude; + add(f); + } + for(int i=0; i res) res = r.d; + add(r); + } + return res; + } + + /** Get a new FlobSet like this, just with a different size. + * Used to combine views. + */ + public FlobSet create(Dimension size) { + return new FlobSet(size, fg, bg, cpt); + } + +} diff --git a/Java/flob/FlobView.java b/Java/flob/FlobView.java new file mode 100644 index 0000000..18f4ff4 --- /dev/null +++ b/Java/flob/FlobView.java @@ -0,0 +1,57 @@ +/* +FlobRaster.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A fairly general interface for drawing a structure + * on the screen using flobs. + * The parameters have been read through the ZOb interface so + * we don't need to worry about those here. + */ + +public interface FlobView { +String rcsid = "$Id$"; + /** Draw a representation of the structure into the FlobSet. + * An implementation of this routine will usually place a number + * of Flobs and Renderables into + * The parameters dims and accursed are redundant but since they + * are used so often, it's just good to have them. + * @param into The FlobSet to place the flobs and decorations into. + * @param fact A factory for constructing flobs. This may be used + * or ignored by the FlobRaster. In general, it should + * be used to draw the "run-of-the-mill" flobs. + * @param view The viewspecs cell in the structure. + * @param dims Three first dims + * @param accursed The cell that the cursor is on + * @see Flob + * @see Renderable + * @see FlobSet + * @see RasterFlobFactory + */ + void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed); +} + + + + diff --git a/Java/flob/GridGeom.java b/Java/flob/GridGeom.java new file mode 100644 index 0000000..c9156df --- /dev/null +++ b/Java/flob/GridGeom.java @@ -0,0 +1,51 @@ +/* +GridGeom.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** An object that describes the geometry of a rectangular grid. + * The grid is assumed to have a center cell i.e. to have an odd + * number of cells. + */ + +public abstract class GridGeom { +String rcsid = "$Id: GridGeom.java,v 1.1 2000/10/21 23:07:35 tjl Exp $"; + /** Initialize the sizes of this grid. + * @param normalcell The size of a "normal" cell. + * @param canvas The size of the whole rectangle this grid is placed + * into + * @return the number of cells in the grid in X and Y directions. + */ + public abstract Dimension setSizes(Dimension normalcell, Dimension canvas); + /** Returns the rectangle corresponding to the given cell. + */ + public final Rectangle getCell(int x, int y) { + return getCell(x, y, new Rectangle()); + } + /** Returns the rectangle corresponding to the given cell, + * placed into the given Rectangle object. + */ + public abstract Rectangle getCell(int x, int y, Rectangle rect); +} + +// vim: set syntax=java : diff --git a/Java/flob/ICView.zob b/Java/flob/ICView.zob new file mode 100644 index 0000000..d483768 --- /dev/null +++ b/Java/flob/ICView.zob @@ -0,0 +1,71 @@ +/* +ICView.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** An integrated-circuit view. Currently we show only + * dimensions. + */ + +public class ICView implements FlobView, ZOb { +public static final String rcsid = "$Id: ICView.zob,v 1.3 2000/11/07 12:38:27 ajk Exp $"; + + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + } + + public void raster(FlobSet into, FlobFactory fact, ZZCell view, + String[]vds, ZZCell accursed) { + Dimension d = into.getSize(); + + Dimension c = fact.getSize(null, 1); + int cw = c.width; + int ch = c.height; + + ZZCell dimhead = ZZCursorReal.get(view.s("d.dims")).h("d.2"); + + fact.makeFlob(into, accursed, accursed, 1, + (d.width-cw) / 2, 0, 1, cw, ch); + int cury = ch+2; + p("ic loop"); + for(ZZCell cur = dimhead; cur != null; ) { + if(accursed.s(cur.t()) != null || + accursed.s(cur.t(),-1) != null) { + fact.makeFlob(into, cur, cur, 1, (d.width-cw) / 2, + cury, 1, cw, ch); + cury += ch+2; + } + cur = cur.s("d.2"); + if(cur == dimhead) break; + p("ic "+cur); + } + p("Out of ic"); + + } + + +} +// vim: set syntax=java : diff --git a/Java/flob/IdiosyncraticFlobFactory.zob b/Java/flob/IdiosyncraticFlobFactory.zob new file mode 100644 index 0000000..f1d7eb7 --- /dev/null +++ b/Java/flob/IdiosyncraticFlobFactory.zob @@ -0,0 +1,98 @@ +/* +IdiosyncraticFlobFactory.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A flob factory that shows each cell with its own view, if + * desired. + * The view should be connected negwards of the cell on + * d.cellview, as a FlobFactory (CellView) ZOb. + */ + +public class IdiosyncraticFlobFactory implements FlobFactory, ZOb { +public static final String rcsid = "$Id: IdiosyncraticFlobFactory.zob,v 1.5 2001/03/18 10:38:26 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + STRUCTPARAMS { + ZOb def + = null; + } + + public FlobFactory getIdiosyncraticCellView(ZZCell c) { + ZZCell h = c.getRootclone().h("d.cellview", true); + if(h == null) return null; + // XXX We *WILL* need a cache of ZObs... + return (FlobFactory)ZZDefaultSpace.readZOb(h); + } + + /** Get the idiosyncratic or default cell view. + * Never returns null. + */ + public FlobFactory getCellView(ZZCell c) { + FlobFactory cv = getIdiosyncraticCellView(c); + if(cv == null) cv = (FlobFactory)def; + if(cv == null) + throw new ZZError("No default view!"); + return cv; + } + + + public Dimension getSize(ZZCell c, float fract) { + if(c == null) + return ((FlobFactory)def).getSize(null, fract); + return getCellView(c).getSize(c, fract); + } + + public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int d, int w, int h) { + return getCellView(c).makeFlob(into, c, handleCell, + fract, x, y, d, w, h); + } + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract) { + return getCellView(c).placeFlob(into, c, handleCell, + fract, x, y, depth, xfract, yfract); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d) { + return getCellView(c).centerFlob(into, c, handleCell, fract, p, + xalign, yalign, depth, d); + } + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) { + return getCellView(c).centerFlob(into, c, handleCell, fract, p, + xalign, yalign, depth); + } + +} + + +// vim: set syntax=java : diff --git a/Java/flob/Level.java b/Java/flob/Level.java new file mode 100644 index 0000000..7c8e2c5 --- /dev/null +++ b/Java/flob/Level.java @@ -0,0 +1,193 @@ +/* +Level.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; + +/** Primitive actions for use with LevelRaster. + * XXX join with LevelRaster? + */ + +public class Level { +public static final String rcsid = "$Id: Level.java,v 1.6 2000/11/07 12:38:27 ajk Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + // A "direction" in the ZZ space + static class DimVector { + String dim; + int dir; + DimVector rev; // The reverse vector + + DimVector(String dim, int dir) { + this.dim = dim; this.dir = dir; rev = new DimVector(this); + } + DimVector(DimVector rev) { dim=rev.dim; dir=-rev.dir; this.rev=rev; } + + ZZCell get(ZZCell c) { return c.s(dim, dir); } + ZZCell end(ZZCell c) { return c.h(dim, dir); } + ZZCell end(ZZCell c, boolean ensuremove) { + return c.h(dim, dir, ensuremove); + } + ZZCell create(ZZCell c) { return c.N(dim, dir); } + ZZCell[] rank(ZZCell c, boolean includeThis) { + return c.readRank(dim, dir, includeThis); + } + } + + + /** A set of dimension vectors: linkdim, targetdim and tunneldim. + */ + static class DimSet { + DimVector linkdim; + DimVector targetdim; + DimVector tunneldim; + DimSet rev; + + DimSet(String dims[]) { + linkdim = new DimVector(dims[0], 1); + targetdim = new DimVector(dims[1], 1); + tunneldim = new DimVector(dims[2], 1); + rev = new DimSet(this); + } + + DimSet(DimSet rev) { + linkdim = rev.targetdim.rev; + targetdim = rev.linkdim.rev; + tunneldim = rev.tunneldim.rev; + this.rev = rev; + } + + DimSet(ZZCell viewc) { + ZZCell[] dimcurs = viewc.readRank("d.dims", 1, false); + linkdim = new DimVector( + ZZCursorReal.get(dimcurs[0]).getText(), 1); + targetdim = new DimVector( + ZZCursorReal.get(dimcurs[1]).getText(), 1); + tunneldim = new DimVector( + ZZCursorReal.get(dimcurs[2]).getText(), 1); + rev = new DimSet(this); + } + + boolean islink(ZZCell c) { + return targetdim.get(c) != null || rev.targetdim.get(c) != null; + } + } + + static class Performer { + ZZCell viewc, c; + DimSet ds; + boolean lnk; + String act; + + Performer(ZZCell viewc) { + this.viewc = viewc; c = ZZCursorReal.get(viewc); + ds = new DimSet(viewc); + lnk = ds.islink(c); + // XXX why doesn't this work: + // act = ZZDefaultSpace.getDirActionWaitingAndClear(viewc); + ZZCell nac = ZZDefaultSpace + .findOnClientlist(c.getSpace(), "NextAction", true); + nac = nac.getOrNewCell("d.1", 1, null); + act = nac.getText(); + nac.setText(""); + } + + public void perf(ZZCell to, DimVector dim) { perf(to, dim, c); } + + public void perf(ZZCell to, DimVector dim, ZZCell from) { + // XXX Extend to HOP and NEW! + // HOP just uses dim; NEW needs to check if link AFTER INSERT + if(act.equals("")) + ZZCursorReal.set(viewc, to); + else if(act.equals("HOP")) { + if(!lnk || dim == null) return; + to.insert(dim.dim, dim.dir, from); + } else if(act.equals("NEW")) { + if(dim == null) return; + ZZCell nc = dim.create(from); + if(ds.islink(nc)) { + if(ds.targetdim.get(nc) == null) ds.targetdim.create(nc); + else ds.rev.targetdim.create(nc); + } + } else + System.out.println("Level module can't do "+act); + } + + public void dir(int d, int b) { + DimSet ds = d < 0 ? this.ds.rev : this.ds; + ZZCell to; + if(lnk) { + if(b == 0) { perf(ds.targetdim.end(c), null); return; } + else if(b < 0) { + to = ds.targetdim.get(c); + if(to != null && ds.targetdim.get(to) != null) + perf(to, ds.targetdim); + } else { + to = ds.targetdim.rev.get(c); + if(to != null) perf(to, ds.targetdim.rev); + } + } else { + if(b < 0) { + perf(ds.linkdim.get(c), ds.linkdim); + } else if(b == 0) { + to = ds.tunneldim.get(c); + ZZCell[] rnk = ds.linkdim.rank(c, false); + if(to == null && rnk.length > 0) + to = rnk[rnk.length / 2]; + perf(to, ds.tunneldim); + } else { + to = ds.linkdim.end(c); + perf(to, ds.linkdim, to); + } + } + } + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + + Performer p = new Performer(view.getViewcell()); + + if(id.equals("UpLeft")) p.dir(-1, -1); + else if(id.equals("Up")) p.dir(-1, 0); + else if(id.equals("UpRight")) p.dir(-1, 1); + else if(id.equals("DownLeft")) p.dir(1, -1); + else if(id.equals("Down")) p.dir(1, 0); + else if(id.equals("DownRight")) p.dir(1, 1); + else System.out.println("Level module: Unknown code '"+id+"'"); + } + + public ZOb newZOb(String id) { + if(id.equals("Raster")) return new LevelView(); + return null; + } + }; +} + + diff --git a/Java/flob/LevelView.zob b/Java/flob/LevelView.zob new file mode 100644 index 0000000..2773b1f --- /dev/null +++ b/Java/flob/LevelView.zob @@ -0,0 +1,492 @@ +/* +LevelRaster.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; +import java.util.*; + +/** A raster for multiple-level structures. + * Interprets two dimensions as many-to-many relationship. Also interprets + * third dimension as one-to-one relationships which are shown the same way + * as the many-to-many relationships. For many-to-many relationships with + * link cells, shows the link cells. + */ + +/* Some XXX'es: + - fix the damn occupiedbreadth bug!!! + - should move the parentlinks in the right place + - primitive actions for leveled visualization (including move) + - loose linking so that new links can be created? or: new link creates + new target, too? or maybe: in loose mode, links w/o target are shown as + that, links w/o target? yeah, way to go. (anyways, should new link also + create new target or not? pbly yes, eh?) + - gaps that shrink; think depthwise gapping through again + */ + +public class LevelView implements FlobView, ZOb { +public static final String rcsid = "$Id$"; + public static boolean dbg = false ; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + /** The size factor applied to cells. */ + float initmul + = (float)1.6; + + /** How many recursion levels shall we render (on both sides of the + * root)? */ + int maxdepth + = 4; + + /** The breadth distance between neigbouring cells. */ + int bgap + = 15; + + /** The depth distance between a cell and a link */ + int dgap + = 10; + + /** The factor of enlargement of cells as they move away + depthwise from the accursed cell. Element 0 is + horizontal, element 1 is vertical. */ + float shrink + = (float)0.7; + + /** The enlargement factor applied to link cells. Think linkshrink! */ + float linkshrink + = (float)0.25; + + /** Should the tree be shown "depthhorizontal", ie. depth rightwards? */ + boolean depthhorizontal + = false; + + /** Should the headcell be used on both dimensions? + * Normally on target dim, tailcell is used. */ + boolean bothhead + = false; + + /** Are links without targets interpreted as targets? + * If two elements are given, the first is used for upstream- and the + * second for downstream connections. */ + boolean[] loose // 1..2 + = new boolean[] { false, false }; + } + + INITIALIZE { + if(loose.length == 1) + loose = new boolean[] { loose[0], loose[0] }; + } + + DimVector[] dims; + Coordinates treegap; // gap converted to a Coordinates instance + Coordinates linkgap; // same with linkshrink applied + Coordinates[] cellsizes; + boolean looseup, loosedown; // XXX ??? + + + // A "direction" in the ZZ space + static class DimVector { + String dim; + int dir; + DimVector rev; // The reverse vector + + DimVector(String dim, int dir) { + this.dim = dim; this.dir = dir; rev = new DimVector(this); + } + DimVector(DimVector rev) { dim=rev.dim; dir=-rev.dir; this.rev=rev; } + + ZZCell get(ZZCell c) { return c.s(dim, dir); } + ZZCell end(ZZCell c) { return c.h(dim, dir); } + ZZCell end(ZZCell c, boolean ensuremove) { + return c.h(dim, dir, ensuremove); + } + ZZCell[] rank(ZZCell c, boolean includeThis) { + return c.readRank(dim, dir, includeThis); + } + } + + class Coordinates { + public int breadth; + public int depth; + + public int x() { return depthhorizontal ? depth : breadth; } + public int y() { return depthhorizontal ? breadth : depth; } + + public void set(int setx, int sety) { + if(depthhorizontal) { + depth = setx; breadth = sety; + } else { + breadth = setx; depth = sety; + } + } + + Coordinates(Dimension d) { set(d.width, d.height); } + Coordinates(int b, int d) { breadth = b; depth = d; } + Coordinates(int i, int j, boolean treecoords) { + if(treecoords) { breadth = i; depth = j; } + else set(i, j); + } + Coordinates(Coordinates c, float fract) { + breadth = (int) (c.breadth * fract); + depth = (int) (c.depth * fract); + } + } + + DimVector[] directeddims(boolean upwards) { + return new DimVector[] { + upwards ? dims[1].rev : dims[0], + upwards ? dims[0].rev : dims[1], + upwards ? dims[2].rev : dims[2] + }; + } + + // STEP 1: Tree generation. This may be overridden + // Note that "children" are cells away from root, and "parents" are + // cells towards root. Only the links to the parents are drawn. + CellInfo connectCell(ZZCell c, ZZCell linkc, ZZCell parentc, + int steps, boolean upwards) { + CellInfo r = new CellInfo(c, linkc, parentc, steps, upwards); + boolean more = steps < maxdepth - 1; + + DimVector[] ds = directeddims(upwards); + DimVector linkdim = ds[0]; + DimVector targetdim = ds[1]; + DimVector tunneldim = ds[2]; + + ZZCell target, parent; + if((target=tunneldim.get(c)) != null && more) + r.childinfo.addElement(connectCell(target, null, c, + steps+1, upwards)); + if((parent=tunneldim.rev.get(c)) != null) + r.parentlinks.addElement(parent); + + ZZCell[] links = linkdim.rank(c, true); + for(int i=0; more && i tdepth ? fdepth : tdepth; + Coordinates size = new Coordinates(cellsizes[depth-1], + linkshrink); + Coordinates fpos = getpos(link.fromc); + Coordinates fsize = getsize(link.fromc); + Coordinates tpos = getpos(link.toc); + Coordinates tsize = getsize(link.toc); + Coordinates pos = new Coordinates( + (fpos.breadth + (fsize.breadth/2) + + tpos.breadth + (tsize.breadth/2) - size.breadth) / 2, + (fpos.depth + fsize.depth + tpos.depth - size.depth) / 2); + boolean succ = put(link.linkc, pos, size, depth, false); + p((succ ? "S" : "Uns")+"uccessfully positioned link cell: "+ + link.linkc.getText()); + } + } + + // STEP 5: Raster the continuum into a flob set + public void raster(FlobSet into, FlobFactory fact, ZZCell view) { + for(Enumeration e = posns.keys(); e.hasMoreElements();) { + ZZCell c = (ZZCell)e.nextElement(); + Coordinates pos = getpos(c); + Coordinates size = getsize(c); + int depth = getdepth(c); + fact.makeFlob(into, c, c, 1, pos.x(), pos.y(), depth, + size.x(), size.y()); + } + for(Enumeration e = linksmalls.elements(); e.hasMoreElements();) { + Link link = (Link)e.nextElement(); + putlink(link.fromc, null, link.toc); + } + for(Enumeration e = links.elements(); e.hasMoreElements();) { + Link link = (Link)e.nextElement(); + int fdepth = getdepth(link.fromc); + int tdepth = getdepth(link.toc); + int depth = fdepth > tdepth ? fdepth : tdepth; + Coordinates fpos = getpos(link.fromc); + Coordinates fsize = getsize(link.fromc); + Coordinates tpos = getpos(link.toc); + Coordinates tsize = getsize(link.toc); + + Coordinates from = new Coordinates( + fpos.breadth + fsize.breadth/2, fpos.depth + fsize.depth); + Coordinates to = new Coordinates( + tpos.breadth + tsize.breadth/2, tpos.depth); + + into.add(new LineDecor(from.x(), from.y(), to.x(), to.y(), + Color.red, depth)); + } + } + } + + + public void initdims(String[] dims) { + this.dims = new DimVector[] { + new DimVector(dims[0], 1), + new DimVector(dims[1], bothhead ? -1 : 1), + new DimVector(dims[2], 1), + }; + } + + public ZZCell look(ZZCell c, int x, int y) { + Coordinates co = new Coordinates(x, y, false); + DimVector d=null, t=null; + if(co.depth == 0) + return null; + else if(co.depth < 0) { + d = dims[0]; + t = dims[3]; + } else { + d = dims[1].rev; + t = dims[3].rev; + } + + if(co.breadth < 0) + return d.get(c); + else if(co.breadth > 0) + return d.end(c, true); + else { + if(t.get(c) != null) return t.get(c); + ZZCell[] rank = d.rank(c, false); + if(rank.length == 0) return null; + return rank[rank.length / 2]; + } + } + + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell c) { + Dimension cs = fact.getSize(null, initmul); + cellsizes = new Coordinates[maxdepth]; + cellsizes[0] = new Coordinates(cs); + for(int i=1; i 1; xw += 2*cur+2*gap[0]) { + ret.width +=2; + cur = (int)(cur * shrink[0]); + } + if(fit) { + xw -= 2*cur+2*gap[0]; + ret.width -= 2; + } + + xs = new int[ret.width + 1]; + cur = (int)(normalcell.width * initmul[0]); + xs[ret.width / 2] = cur; + for(int i=1; i 1; yw += 2*cur+2*gap[1]) { + ret.height +=2; + cur = (int)(cur * shrink[1]); + } + if(fit) { + yw -= 2*cur+2*gap[1]; + ret.height -= 2; + } + + ys = new int[ret.height + 1]; + cur = (int)(normalcell.height * initmul[1]); + ys[ret.height / 2] = cur; + for(int i=1; i2; nx++) { + xw += 2 * (int)curl; + curl *= shrink[0]; + } + + int ny = 0; + curl = maxsz.height; + for(int yw = 0; yw <= fs.height - maxsz.height && curl>2; ny++) { + yw += 2 * (int)curl; + curl *= shrink[1]; + } + + nx *= 2; + ny *= 2; + ZZCell[][] grid = new ZZCell[nx][ny]; + + int[] xsz = new int[nx+1]; + int[] ysz = new int[ny+1]; + + xsz[0] = maxsz.width / 2; + xsz[1] = maxsz.width; + ysz[0] = 2*maxsz.height; + ysz[1] = maxsz.height; + + curl = maxsz.width; + for(int i=0; i 0 && cur != null; x--) { ld.detect(cur); + cur = cur.s(dims[0], -1); if(cur == xhead) break; + grid[x][cy] = cur; + } + + ld.reset(); + cur = accursed; + for(int y = cy-1; y > 0 && cur != null; y--) { ld.detect(cur); + cur = cur.s(dims[1], -1); if(cur == yhead) break; + grid[cx][y] = cur; + } + + // Poswards + ld.reset(); + cur = accursed; + for(int x = cx+1; x < nx && cur != null; x++) { ld.detect(cur); + grid[x][cy] = cur = cur.s(dims[0], 1); + } + ld.reset(); + cur = accursed; + for(int y = cy+1; y < ny && cur != null; y++) { ld.detect(cur); + grid[cx][y] = cur = cur.s(dims[1], 1); + } + + + // Other headcells + for(int x = 1; x < nx; x ++) + if(grid[x][cy] != null) { + grid[x][0] = grid[x][cy].h(dims[1], -1); + if(grid[x][0]!=null) + heads.put(grid[x][0], new Integer(x)); + } + for(int y = 1; y < ny; y ++) + if(grid[cx][y] != null) { + ZZCell c = grid[0][y] = grid[cx][y].h(dims[0], -1); + if(c!=null) + heads.put(c, new Integer(0)); + c = c.s(dims[0], 1); + ld.reset(); + while(c!=null) { // Show other intersections + ld.detect(c); + Integer xpos = (Integer)heads.get(c.h(dims[1], -1)); + if(xpos!=null) + grid[xpos.intValue()][y] = c; + c = c.s(dims[0], 1); + } + } + + + LineDecor.Builder bdline = new LineDecor.Builder(into, Color.red); + bdline.startl(400, 1); + + // Find out which cells are shown + + Hashtable shown = new Hashtable(); + + for(int x = 0; x < nx; x++) { + for( int y = 0; y < ny; y++) { + if(grid[x][y]!=null) + shown.put(grid[x][y], grid[x][y]); + } + } + + // Render the flobs + + for(int x = 0; x < nx; x ++) { + for( int y = 0; y < ny; y ++) { + if(grid[x][y] == null) continue; + int xcoord = xsz[x]; + int ycoord = ysz[y]; + int width = xsz[x+1] - xcoord; + int height = ysz[y+1] - ycoord; + + if(x != 0 && y != 0 && heads.get(grid[x][y])!=null) + continue; + + Flob fl = fact.makeFlob(into, grid[x][y], grid[x][y], + initmul * height / (float)maxsz.height, + xcoord, ycoord, 1, width, height); + /* if(x == 0 || y == 0) + fl.flobPath="headcell";*/ + + // Place a red line if the neighbour isn't shown + ZZCell c = grid[x][y]; + for(int dx=-1;dx<=1;dx+=2) { + ZZCell n = c.s(dims[0], dx); + if(n!=null && shown.get(n)==null + && (y!=0 || (x+dx>0 && x+dx0 && y+dy=0; i--) { + cury -= getfontmet(getFontScale(i-ctr, doBillow)).getHeight(); + } + + res.x = startx; res.width = width; + res.y = cury; + + // Downwards from center. + // start-splitcellflob needs very careful attention. + + /** Current offset in the whole string. + */ + int curoffs = 0; + /** Current line. + */ + int curline = 0; + + /** Current X-coordinate. + */ + int curx = startx; + + int fi = getFontScale(curline - ctr, doBillow); + Font f = getfont(fi); + FontMetrics fm = getfontmet(fi); + + SplitCellFlob1 latest = null; + + first = true; + for(ZZCell h = head; + h != null && (first || h != head); h = h.s(dim, 1)) { + first = false; + + final String st = h.getText(); + final int len = st.length(); + int nth = 0; + SplitCellFlob1 parent = null; + + // Find the cursors on this cell. Only one is shown. + int curs = ZZCursorReal.NO_OFFSET; + ZZCell ccurs = h; + while((ccurs = ccurs.s("d.cursor", 1))!=null) { + curs = ZZCursorReal.getOffs(ccurs); + if(curs != ZZCursorReal.NO_OFFSET) break; + } + + if(h.s("d.cut", 1) != null) { + // There was a cut. + into.add(new LineDecor(curx, cury, curx, cury+fm.getHeight(), + Color.red, 1)); + } + + while(curoffs + len - nth > linestops[curline+1]) { + p("Parent: "+nth+" "+len+" "+curline+" "+linestops[curline+1]); + SplitCellFlob1 cur = new SplitCellFlob1( + curx, cury, 100, fm.stringWidth(st.substring(nth, + nth+ + (linestops[curline+1] - curoffs))), + fm.getHeight(), h, f, fm, parent, + nth, linestops[curline+1]-curoffs, xormode, bgcolor); + if(bgcolor == null) cur.showCursor(); + cur.setPrev(latest); latest = cur; + if(curs != ZZCursorReal.NO_OFFSET) + addCurs(into, cur, curs); + parent = cur; + into.add(cur); + + // Split it. + nth += linestops[curline+1] - curoffs; + curoffs = linestops[curline+1]; + curline ++; + cury += fm.getHeight(); + curx = startx; + fi = getFontScale(curline - ctr, doBillow); + f = getfont(fi); + fm = getfontmet(fi); + if(curline >= linestops.length - 1) { + p("LAST LINE: ALL OUT"); + break; + } + } + if(curline >= linestops.length - 1) + break; + + p("Last: "+nth+" "+len+" "+curline+" "+linestops[curline+1]+" "+ + st.length()); + int w = 0; + String substr = st.substring(nth, len); + p("Substr: "+substr); + SplitCellFlob1 last = new SplitCellFlob1( + curx, cury, 100, + (w = fm.stringWidth(substr)), + fm.getHeight(), h, f, fm, parent, nth, len-nth, xormode, bgcolor); + if(bgcolor == null) last.showCursor(); + last.setPrev(latest); latest = last; + + if(curs != ZZCursorReal.NO_OFFSET) + addCurs(into, last, curs); + curoffs += len-nth; + curx += w; + into.add(last); + } + p("FINISHED"); + res.height = cury - res.y + fm.getHeight(); + return res; + } + + public Rectangle raster(FlobSet into, ZZCell c, int offs, boolean doBillow, + int startx, int starty) { + return raster(into, c, offs, doBillow, startx, starty, + SplitCellFlob1.XOR_NO); + } + + private void addCurs(FlobSet into, SplitCellFlob1 sf, int ind) { + if(!(ind >= sf.start && ind <= sf.start + sf.n)) + return; + int x = sf.getStrX(ind); + if(x >= 0) + into.add(new LineDecor(x, sf.y, x, sf.y+sf.h, + Color.black, sf.d)); + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + ZZCell c = ZZCursorReal.get(view); + int offs = ZZCursorReal.getOffs(view); + int xormode = SplitCellFlob1.XOR_LINE; + if(offs == ZZCursor.NO_OFFSET) { + offs = 0; + xormode = SplitCellFlob1.XOR_SOLID; + } + + if(!xor) xormode = SplitCellFlob1.XOR_NO; + + Dimension d = into.getSize(); + int cy = d.height / 2; + + raster(into, c, offs, billow, 0, cy, xormode); + } + + // public VStreamRaster() { } + +} + +// vim: set syntax=java : diff --git a/Java/flob/Renderable.java b/Java/flob/Renderable.java new file mode 100644 index 0000000..cfb4749 --- /dev/null +++ b/Java/flob/Renderable.java @@ -0,0 +1,88 @@ +/* +Renderable.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + + +public abstract class Renderable { +public static final String rcsid = "$Id: Renderable.java,v 1.10 2001/03/17 20:13:08 bfallenstein Exp $"; + + public int d; + + /** Render this thing. + */ + abstract public void render(Graphics g); + + /** Render this thing. + * Simply calls render(g). + * @param orig The top-level graphics object without translations, + * clippings, rotations, etc. + */ + public void render(Graphics g, Graphics orig) { render(g); } + + /** Translate the coordinates of this Renderable by (x, y) + * I.e., add x from the x-coordinate and y from the y-coordinate. + * This is used to translate between coordinate systems. + * @returns False if translating is not supported. + */ + public boolean translate(int x, int y) { + return false; + } + + + /** Do a stable depth-sort of renderables. + * Of two renderables on the same depth, the relative order remains. + * Uses radix sort for extreme speed. + */ + static public void depthSort(Renderable[] it, int nit) { + Renderable[][] ftmp = new Renderable[][] { it, new Renderable[nit] }; + Renderable[][] ftmp2 = new Renderable[2][nit]; + Renderable[][] fs; + int[] n = new int[] { nit, 0 }; + int[] newn = new int[2]; + int[] nex = null; + int mx = 0; + for(int i=0; i mx) mx = it[i].d; + } + for(int bit = 1; mx >= bit && bit!=0; bit <<= 1) { + for(int bin=0; bin<2; bin++) { + for(int i=0; i= col.length) return false; + if(!repeat && done.get(c) != null) return false; + col[nth] = c; + done.put(c, c); + if(row) + geom.getCell(cother, nth, rect); + else + geom.getCell(nth, cother, rect); + place(fact, into, c, ideal, rect); + return true; + } + }); + + final int lother = (row ? gs.width : gs.height); + + for(int i = 0; i= lother) return false; + if(!repeat && done.get(c) != null) return false; + done.put(c, c); + if(row) + geom.getCell(nth, coord, rect); + else + geom.getCell(coord, nth, rect); + place(fact, into, c, ideal, rect); + return true; + } + }); + } + + linker.decorate(into, "", view); + } + + + +} +// vim: set syntax=java : diff --git a/Java/flob/SceneFlob.java b/Java/flob/SceneFlob.java new file mode 100644 index 0000000..5cfecfb --- /dev/null +++ b/Java/flob/SceneFlob.java @@ -0,0 +1,148 @@ +/* +SceneFlob.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** Flob which contains flobset, possibly transformed. + * This is subclassed by e.g. ZZDrawingJ2D. + */ + +public abstract class SceneFlob extends BoxedFlob { +public static final String rcsid = "$Id: SceneFlob.java,v 1.8 2001/03/18 17:50:16 bfallenstein Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + FlobSet sc; + + public SceneFlob(int x, int y, int d, int w, int h, ZZCell c, FlobSet sc) { + super(x,y,d,w,h,c); + this.sc = sc; + sc.sflob = this; + } + + /** The flobs that are important to interpolate + * even when level-of-detail is small + */ + Flob[] important; + + /** Set the important-to-interpolate flobs. + */ + public void setImportant(Flob[] what) { + important = what; + } + + /** Whether this is a focused sceneflob, i.e.whether level-of-detail + * is high. + */ + boolean focus; + + public void setFocus(boolean focus) { + this.focus = focus; + } + + /** The other sceneflob we are currently prepared to interpolate to. + */ + SceneFlob interpPrep; + + /** The scene flob this one is in. + * This is needed to convert coordinates to top-level; and that is needed + * to create connections between windows. + */ + SceneFlob parent; + + /** Transform the given points between the internal and external coordinates. + * @param toExt Whether to transform internal to external or vice versa. + */ + public abstract void transform(double[] srcPtr, double[]dstPts, boolean toExt); + + /** Transform the given point between the internal and external coordinates. + * @param toExt Whether to transform internal to external or vice versa. + */ + public abstract Point transform(Point src, Point dst, boolean toExt); + + /** Transform the given points between the internal and top-level coordinates. + * @param toTop Whether to transform internal to top-level or vice versa. + */ + public void transformTop(double[] srcPtr, double[] dstPts, boolean toTop) { + if(toTop) transform(srcPtr, dstPts, true); + if(parent != null) + parent.transformTop(srcPtr, dstPts, toTop); + if(!toTop) transform(srcPtr, dstPts, false); + } + + /** Transform the given point between the internal and top-level coordinates. + * @param toTop Whether to transform internal to top-level or vice versa. + */ + public Point transformTop(Point src, Point dst, boolean toTop) { + if(toTop) transform(src, dst, true); + if(parent != null) + parent.transformTop(src, dst, toTop); + if(!toTop) transform(src, dst, false); + return dst; + } + + /** Make this graphics so that we can render into it with the correct + * transformation. + */ + abstract void prepareGraphics(Graphics g, float interpFract); + + public void render(Graphics g0) { render(g0, g0); } + public void render(Graphics g0, Graphics orig) { + Graphics g = g0.create(); + prepareGraphics(g, 0); + sc.render(g, orig); + g.dispose(); + } + + public void renderInterp(Graphics g0, float fract) { + if(!(interpTo instanceof SceneFlob)) return; + // p("sceneflob renderinterp"); + // Here we test the level-of-detail stuff. + if(interpTo != interpPrep) { + interpPrep = (SceneFlob)interpTo; + // p("Prepinterp sceneflob: "+focus+" "+interpPrep.focus+" "+important); + if(focus || interpPrep.focus || important == null) + sc.prepareInterp(interpPrep.sc); + else + sc.prepareInterp(interpPrep.sc, important); + } + Graphics g = g0.create(); + prepareGraphics(g, fract); + sc.renderInterp(g, ((SceneFlob)interpTo).sc, fract); + g.dispose(); + } + + public boolean isInterpUseful() { return true; } + + public Object hit(int x, int y) { + Point p = new Point(x,y); + Point d = new Point(); + transform(p,d, false); + return sc.getObjectAt(d.x, d.y); + } + + public FlobSet getFlobSet(){ return sc;} + +} diff --git a/Java/flob/SimpleBeamer.zob b/Java/flob/SimpleBeamer.zob new file mode 100644 index 0000000..4415c0c --- /dev/null +++ b/Java/flob/SimpleBeamer.zob @@ -0,0 +1,256 @@ +/* +SimpleBeamer.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A decorator which draws beams between overlapping SpanFlobs. + * This is a tricky job: among other things, we are responsible for + * the overall aesthetic effect of beams. + * Currently, we try to draw the beams between the topmost + * flobs last so that the beams have a consistent ordering w.r.t. + * the Z axis. This is not trivial, since we also have to + * draw neighbouring beams using the same color. + */ + +public class SimpleBeamer implements FlobDecorator { +public static final String rcsid = "$Id: SimpleBeamer.zob,v 1.7 2000/09/19 10:31:59 ajk Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + + /** The depth where to put the beam graphics. + */ + int depth + = 1000; + + } + + // Used for checking whether the connection between two spans + // is handled already. + private class Pair { + Object a; Object b; + public Pair(Object a, Object b) { + this.a = a; + this.b = b; + } + public int hashCode() { + return a.hashCode() ^ b.hashCode(); + } + public boolean equals(Object o) { + Pair p = (Pair)o; + return (a==p.a && b==p.b) || (b==p.a && a==p.b); + } + } + + static public Color getSpanColor() { + return new Color( + (float)(Math.random() + 1) / 2, + (float)(Math.random() + 1) / 2, + (float)(Math.random() + 1) / 2 + ); + } + + int[] xy = new int[16]; + + protected void putBeam(BeamDecor.Builder bb, + SpanFlob[] sfs, Span[] sps, + Color c) { + p("Putbeam"); + int ssep = (int)(sps[0].getStartOffs() - sps[1].getStartOffs()); + int esep = (int)(sps[0].getEndOffs() - sps[1].getEndOffs()); + + int x0=0, x1=0, w0=(int)sps[0].length(), w1=(int)sps[1].length(); + + if(ssep > 0) x1 = ssep; + else x0 = -ssep; + + if(esep > 0) w0 -= esep; + else w1 += esep; + + Rectangle r0 = sfs[0].getRectangle(x0, w0); + Rectangle r1 = sfs[1].getRectangle(x1, w1); + + // Then, some difficult manipulation to get the points. + + Rectangle a=null; + + // left side + if(r0.x < r1.x) { a = r0; } else { a = r1; } + xy[0] = a.x; xy[8] = a.y; + xy[1] = a.x; xy[9] = a.y+a.height; + // bottom side + if(r0.y+r0.height > r1.y+r1.height) { a = r0; } else { a = r1; } + xy[2] = a.x; xy[10] = a.y+a.height; + xy[3] = a.x+a.width; xy[11] = a.y+a.height; + // right side + if(r0.x+r0.width > r1.x+r1.width) { a = r0; } else { a = r1; } + xy[4] = a.x+a.width; xy[12] = a.y+a.height; + xy[5] = a.x+a.width; xy[13] = a.y; + // top + if(r0.y < r1.y) { a = r0; } else { a = r1; } + xy[6] = a.x+a.width; xy[14] = a.y; + xy[7] = a.x; xy[15] = a.y; + + bb.b(xy, c); + + } + + /** Return: whether to continue. + */ + static boolean moveBack( SpanFlob[] sfs, + Span[] spans) { + long l1 = spans[0].getStartOffs(); + long l2 = spans[1].getStartOffs(); + if(l1 == l2) { + // Check if previous spans end at same point. + sfs[0] = sfs[0].getPrev(); if(sfs[0] == null) return false; + sfs[1] = sfs[1].getPrev(); if(sfs[1] == null) return false; + spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false; + spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false; + if(spans[0].getEndOffs() != spans[1].getEndOffs()) return false; + return true; + } + if(l1 > l2) { + Span tmp = spans[0]; + sfs[0] = sfs[0].getPrev(); if(sfs[0] == null) return false; + spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false; + return spans[0].isAppendable(tmp); + } else { + Span tmp = spans[1]; + sfs[1] = sfs[1].getPrev(); if(sfs[1] == null) return false; + spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false; + return spans[1].isAppendable(tmp); + } + } + static boolean moveForw( SpanFlob[] sfs, + Span[] spans) { + long l1 = spans[0].getEndOffs(); + long l2 = spans[1].getEndOffs(); + if(l1 == l2) { + // Check if previous spans end at same point. + sfs[0] = sfs[0].getNext(); if(sfs[0] == null) return false; + sfs[1] = sfs[1].getNext(); if(sfs[1] == null) return false; + spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false; + spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false; + if(spans[0].getStartOffs() != spans[1].getStartOffs()) return false; + return true; + } + if(l1 < l2) { + Span tmp = spans[0]; + sfs[0] = sfs[0].getNext(); if(sfs[0] == null) return false; + spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false; + return tmp.isAppendable(spans[0]); + } else { + Span tmp = spans[1]; + sfs[1] = sfs[1].getNext(); if(sfs[1] == null) return false; + spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false; + return tmp.isAppendable(spans[1]); + } + } + + public void decorate(final FlobSet into, final String path, + final ZZCell view) { + + p("Putting beams..."); + final BeamDecor.Builder bb = new BeamDecor.Builder(into); + + final SpanSet ss = new SpanTree(); + + final Hashtable done = new Hashtable(); + + final SpanFlob[] sfs = new SpanFlob[2]; + final Span[] sps = new Span[2]; + final Span[] sps0 = new Span[2]; + + // Starts from the surface, goes deeper. + // BeamDecor renders first-put ones last, which is + // exactly right for this. + + // XXX WRONG! + // ss gets added things so that the span gets + // drawn when the deeper one is reached, not earlier. + // hmm... + into.iterDepth(new FlobSet.DepthIter() { + public void act(Flob[] flobs, int start, int n) { + bb.startl((n+8)*4, depth); + for(int f = start; f 0) { + p("Obj: "+ovs[0]); + } else continue; + + + for(int i=0; i= 14) { + g.drawRect(mx-2, my-2, mw+2, mh+2); + } + } +} + + diff --git a/Java/flob/SimpleFlobConnector.zob b/Java/flob/SimpleFlobConnector.zob new file mode 100644 index 0000000..42a1169 --- /dev/null +++ b/Java/flob/SimpleFlobConnector.zob @@ -0,0 +1,109 @@ +/* +SimpleFlobConnector.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A simple but powerful raster which uses flob coordinates. + * Z is the selection dimension, X and Y are the flob dimension + * specifications. + */ + +public class SimpleFlobConnector implements FlobDecorator, ZOb { +public static final String rcsid = "$Id: SimpleFlobConnector.zob,v 1.9 2000/09/19 10:31:59 ajk Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + + /** Whether the selection dimension is always d.2 or + * whether it is the Z dimension. + */ + boolean selectd2 + = true; + + /** The path from one handle cell to another. + */ + ZZPath connection + = null; + } + + int count; + // public SimpleFlobConnector() { } + + // Always middle - to - middle. + public void decorate(final FlobSet f, final String path, + final ZZCell view) { + + p("SIMPLEFLOBCNNETOR DECORATE!"); + count = 0; + + final Hashtable done = new Hashtable(); + + if(connection == null) + throw new ZZError("Must provide value for FlobConnector connection"); + + final ConnectionLineDecor.Builder clb = new + ConnectionLineDecor.Builder(f, null); + clb.startl(100, 1); + + f.iterDepth(new FlobSet.DepthIter() { + public void act(Flob[] flobs, int start, int n) { + + for(int i=start; i + * XXX Rework the nextPart, parent, next, prev relation! + */ + +public class SplitCellFlob1 extends Flob implements SpanFlob { +public static final String rcsid = "$Id: SplitCellFlob1.java,v 1.36 2001/04/02 20:21:43 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + // The XOR modes. + static public final int XOR_NO = 0; + static public final int XOR_LINE = 1; + static public final int XOR_FRAME = 2; + static public final int XOR_SOLID = 3; + + public int xormode = XOR_NO; + + + /** Whether to clip before drawing the contents of this flob. */ + public boolean doClip = false; + + /** The next part of this flob. */ + SplitCellFlob1 nextPart; + + /** The first of this chain. */ + public SplitCellFlob1 parent; + + /** Index of first character. */ + public int start; + + /** Number of characters. */ + public int n; + + /** The text in this flob (substring of c.getText()). + * This text is allowed to be modified from outside to allow e.g. for + * firstcap. Doing that in any way that does not retain the number + * and offsets of characters will screw up beams and many other + * things so don't do that ;) + */ + public String txt; + + public SpanFlob prev, next; + public SpanFlob getPrev() { return prev; } + public SpanFlob getNext() { return next; } + public void setPrev(SpanFlob sf) { + prev = sf; + if(prev != null) prev.setNext(this); + } + public void setNext(SpanFlob sf) { next = sf; } + + public Color bg, fg = Color.black; + + Font f; + FontMetrics fm; + + /** Set the background of this flob to the color of the topmost cursor. */ + public void showCursor() { + // Only take topmost cursor's color + ZZCell curs = getCell().s("d.cursor", 1); + if(curs != null) { + bg = ZZCursorReal.getColor(curs); + if(bg == null) + pa("No cursor color!"); + } else + p("No cursors on this cell."); + } + + static boolean intostr = false; + public String toString() { + if(intostr) return super.toString(); + intostr = true; + String ret = super.toString() + "(SPLCF1 bg="+bg+ + "Parent: ("+parent+") stn: "+start+" "+n+" Txt:'"+txt+"' Cell:"+c + +" next: "+nextPart + + " )"; + intostr = false; + return ret; + } + + public SplitCellFlob1(int x, int y, int d, int w, int h, + ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent, + int start, int n) { + this(x, y, d, w, h, c, f, fm, parent, start, n, null); + } + + public SplitCellFlob1(int x, int y, int d, int w, int h, + ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent, + int start, int n, Color bg) { + this(x, y, d, w, h, c, + c.getText().substring(start, start+n), + f, fm, parent, start, n, bg); + } + + public SplitCellFlob1(int x, int y, int d, int w, int h, + ZZCell c, String txt, Font f, FontMetrics fm, SplitCellFlob1 parent, + int start, int n, Color bg) { + + super(x, y, d, w, h, (parent==null ? c : null)); + p("SplitCellFlob: "+x+" "+y+" "+d+" "+w+" "+h+" "+c+" "+f+" "+ + fm+" "+parent+" "+start+" "+n+" "+bg); + this.f = f; this.fm = fm; + if(parent != null) { + if(!parent.c.equals(c)) + throw new ZZError( + "Parent and child splitcellflob must have same cell: "+c+ + " "+parent.c); + SplitCellFlob1 prev = parent; + while(prev.nextPart != null) prev = prev.nextPart; + prev.nextPart = this; + this.parent = (parent.parent == null ? parent : parent.parent); + } + this.start = start; this.n = n; + this.txt = txt; + this.bg = bg; + p("Created splitcellflob: "+this); + } + + public SplitCellFlob1(int x, int y, int d, int w, int h, + ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent, + int start, int n, int xormode) { + this(x, y, d, w, h, c, f, fm, parent, start, n); + } + + public SplitCellFlob1(int x, int y, int d, int w, int h, + ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent, + int start, int n, int xormode, Color bg) { + this(x, y, d, w, h, c, f, fm, parent, start, n, bg); + this.xormode = xormode; + } + + public final ZZCell getCell() { + return (parent==null ? c : parent.c); + } + + public Span getSpan() { + Span sp = getCell().getSpan(); + if(sp == null) return null; + // XXX test for samity + return sp.subSpan(start, start+n); + } + + public Rectangle getRectangle(Span s) { + Span t = getCell().getSpan(); + int so = (int)(s.getStart().getOffs() - t.getStart().getOffs()); + int eo = (int)(s.getEnd().getOffs() - t.getStart().getOffs()); + int sw = fm.stringWidth(txt.substring(0, so)); + int ew = fm.stringWidth(txt.substring(0, eo)); + return new Rectangle(x + sw, y, ew-sw, h); + } + public Rectangle getRectangle(int offs, int end) { + int sw = fm.stringWidth(txt.substring(0, offs)); + int ew = fm.stringWidth(txt.substring(0, end)); + return new Rectangle(x + sw, y, ew-sw, h); + } + + /* Very quick hack to interpolate from and to non-span flobs: + * let this read render(g0, x, y, d, w, h) instead of render(g0). Not at + * all what the interpolation SHOULD look like, but better than the + * nothing we've had before. + */ + public void render(Graphics g0, int x, int y, int d, int w, int h) { + int my = y + h - fm.getDescent(); + // p("SpliCellFlob drawString: '"+txt+"' "+x+" "+my+" "+fg+" "+bg); + + Graphics g = g0.create(); + Color bu = g.getColor(); + if (doClip) g.clipRect(x, y, w, h); + g.setFont(f); + if(bg != null) { + g.setColor(bg); + g.fillRect(x, y, w, h); + } + if(fg != null) g.setColor(fg); + else g.setColor(bu); + p("SpliCellFlob drawString: '"+txt+"' "+x+" "+my+" "+fg+" "+bg); + g.drawString(txt, x, my); + + g.dispose(); + + if(nextPart != null) + nextPart.render(g0); + } + + /** Render an interpolated version. + * This is the trickiest routine of this class since we do + * want to get the interpolation behaviour just right so that all text + * pieces flow to where they are supposed to. + */ + public void renderInterp(Graphics g0, float fract) { + if(interpTo==null) return; + if(!(interpTo instanceof SplitCellFlob1)) { + super.renderInterp(g0, fract); + return; + } + SplitCellFlob1 t = this; + SplitCellFlob1 r = (SplitCellFlob1)interpTo; + + Graphics g = g0.create(); + Shape clip = g.getClip(); + if(fg != null) g.setColor(fg); + + // Render the correct fragment of the two and advance. + while(t!=null && r!=null) { + if(t.start+t.n < r.start) { t = t.nextPart; continue; } + if(t.start > r.start+r.n) { r = r.nextPart; continue; } + int st = 0; + int en = 0; + if(t.start < r.start) st = r.start; + else st = t.start; + if(t.start+t.n < r.start+r.n) en = t.start+t.n; + else en = r.start+r.n; + int tx = t.getStrX(st); + int rx = r.getStrX(st); + int x = (int)(tx + (rx-tx)*fract); + int ty = t.y + t.h - t.fm.getDescent(); + int ry = r.y + r.h - r.fm.getDescent(); + int y = (int)(ty + (ry-ty)*fract); + int tw = t.getStrX(en) - tx; + int rw = r.getStrX(en) - rx; + int w = (int)(tw + (rw-tw)*fract); + int realy = (int)(t.y + (r.y-t.y)*fract); + if (doClip) { + g.clipRect(x, realy, w, t.h); + } + if(bg != null) { + Color col = g.getColor(); + g.setColor(bg); + g.fillRect(x, realy, tw, t.h); + g.setColor(col); + } + g.setFont(t.f); + g.drawString(t.txt.substring(st-t.start, en-t.start), x, y); + if (doClip) g.setClip(clip); + if(t.start+t.n < r.start+r.n) t = t.nextPart; + else r = r.nextPart; + } + g.dispose(); + } + + public boolean renderXORLine(Graphics g, int cx, int cy) { + ZZCursorVirtual vc = (ZZCursorVirtual)hit(cx, cy); + if(vc==null) return false; + g.setColor(Color.black); + g.setXORMode(Color.white); + int xo = fm.stringWidth(txt.substring(0, vc.getOffs()-start)); + g.drawLine(x+xo, y, x+xo, y+h); + return true; + } + + public void renderXORFrame(Graphics g, boolean left, boolean right) { + // XXX instead of using f.h-1 & f.y+1, just don't create overlapping + // XXX SplitCellFlobs any more? + g.setColor(Color.black); + g.setXORMode(Color.white); + SplitCellFlob1 f = parent != null ? parent : this; + if(left) g.drawLine(f.x, f.y+1, f.x, f.y+f.h-1); + while(true) { + g.drawLine(f.x, f.y+1, f.x+f.w, f.y+1); + g.drawLine(f.x, f.y+f.h-1, f.x+f.w, f.y+f.h-1); + if(f.nextPart != null) f = f.nextPart; + else break; + } + if(right) g.drawLine(f.x+f.w, f.y+1, f.x+f.w, f.y+f.h-1); + } + + public void renderXORSolid(Graphics g) { + g.setColor(Color.black); + g.setXORMode(Color.white); + SplitCellFlob1 f = parent != null ? parent : this; + for(; f != null; f = f.nextPart) { + g.fillRect(f.x, f.y, f.w, f.h); + } + } + + public boolean renderXOR(Graphics g, int cx, int cy) { + if(!insideRect(cx, cy)) return false; + if(xormode == XOR_NO) return true; // XXX or false? + else if(xormode == XOR_LINE) return renderXORLine(g, cx, cy); + else if(xormode == XOR_FRAME) renderXORFrame(g, true, true); + else if(xormode == XOR_SOLID) renderXORSolid(g); + else throw new ZZError("SplitCellFlob1: Unknown XOR mode"); + return true; + } + + /** Get the x-coordinate of a given letter. + * @param ind The index, given as starting from the beginning of the cell. + * Must satisfy start <= ind <= start+n + */ + public int getStrX(int ind) { + ind -= start; + return x + fm.stringWidth(txt.substring(0,ind)); + } + + public Object hit(int x, int y) { + if(!insideRect(x, y)) return null; + if(xormode == XOR_FRAME || xormode == XOR_SOLID) + return new ZZCursorVirtual(getCell(), ZZCursorVirtual.NO_OFFSET); + int ind = ZZUtil.findStringHit(txt, x-this.x, fm) + start; + return new ZZCursorVirtual(getCell(), ind); + } + + /** Add a line cursor at the given index into the given flobset. + */ + public void addCurs(FlobSet into, int ind, Color c) { + if(parent != null) + parent.addCurs0(into, ind, c); + else + addCurs0(into, ind, c); + } + private void addCurs0(FlobSet into, int ind, Color c) { + if(ind >= start && ind <= start + n) { + int x = getStrX(ind) - 1; + into.add(new LineDecor(x, y, x, y+h, + c, d)); + } + if(nextPart != null) + nextPart.addCurs0(into, ind, c); + } + +} diff --git a/Java/flob/SplitView.zob b/Java/flob/SplitView.zob new file mode 100644 index 0000000..3baecd9 --- /dev/null +++ b/Java/flob/SplitView.zob @@ -0,0 +1,78 @@ +/* +SplitView.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.awt.*; + +/** A view that shows the ctrl and data windows in one. */ + +public class SplitView implements FlobView, ZOb { +public static final String rcsid = "$Id: SplitView.zob,v 1.1 2000/12/26 15:20:42 bfallenstein Exp $"; + /** Should we print out debugging info? */ + public static boolean dbg = false; + static final void p(String s) { if(dbg) pa(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS {} + + public void raster(FlobSet into, FlobFactory fact, + ZZCell win, String[] dims, ZZCell accursed) { + Dimension size = new Dimension(into.getSize()); + size.width = size.width / 2; + FlobSet set = into.create(size), otherset = into.create(size); + + FlobView view = new VanishingView(); + view.raster(set, fact, win, dims, accursed); + + boolean isctrl = false; + ZZCell otherwin = win.s("d.ctrlview", -1); + if(otherwin == null) { otherwin=win.s("d.ctrlview"); isctrl=true; } + if(otherwin == null) + throw new ZZError("SplitView invoked for a window which is " + + "not in a control/data pair!"); + + String[] otherdims = ZZDefaultSpace.getDimList(otherwin); + ZZCell otheracc = ZZCursorReal.get(otherwin); + + ZZCell c = ZZDefaultSpace.findInheritableParam(otherwin, "View"); + ZZCell rastname = ZZCursorReal.get(c); + + ZOb frz = ZZDefaultSpace.readZOb(rastname); + FlobView otherview = null; + if(frz != null && frz instanceof FlobView) { + otherview = (FlobView)frz ; + } else { + System.out.println("getScene: invalid type: "+frz); + otherview = new NullView(); + } + + otherview.raster(otherset, fact, otherwin, otherdims, otheracc); + + if(isctrl) { + FlobSet tmp = set; + set = otherset; + otherset = tmp; + } + + into.fetch(otherset, 0, 0, 0); + into.fetch(set, size.width, 0, 0); + } +} diff --git a/Java/flob/StdLinks.zob b/Java/flob/StdLinks.zob new file mode 100644 index 0000000..8979f20 --- /dev/null +++ b/Java/flob/StdLinks.zob @@ -0,0 +1,208 @@ +/* +StdLinks.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +public class StdLinks implements FlobDecorator { +public static final String rcsid = "$Id: StdLinks.zob,v 1.13.10.1 2002/03/07 21:02:41 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + + /** Whether to draw badly directioned links as splines. + */ + boolean splines + = true; + + /** Spline radius. + */ + float splinvec + = 50; + + /** Whether the tight-brick mode is used for cells with + * non-shown links. + */ + boolean tightDefault + = false; + + /** Whether to draw the links the old way, between corners. + */ + boolean useCorners + = false; + + } + + static int[] xoffs = new int[] {1, 0, 1}; + static int[] yoffs = new int[] {0, 1, 1}; + + public void decorate(final FlobSet f, final String path, + final ZZCell view) { + final String[] dims = ZZDefaultSpace.getDimList(view); + p("DECORATE STDLINKS"); + // Cells whose connections were done. + final Hashtable done = new Hashtable(); + final Point p1 = new Point(), p2 = new Point(); + + final LineDecor.Builder ldb = new LineDecor.Builder(f, null); + + f.iterDepth(new FlobSet.DepthIter() { + public void act(Flob[] flobs, int start, int n) { + p("STDLINKS ACT "+start+" "+n+" "+flobs[start].d); + + ldb.startl(4*n, flobs[start].d+1); + + for(int i=start; i= xoffs.length) break; + // p(" Dim: "+dims[d]); + + for(int dir=-1; dir<=1; dir += 2) { + ZZCell neigh = c.s(dims[d], dir); + p(" Neigh: "+neigh+" "+ + (neigh!=null?neigh.getText():"")+ + " "+(neigh==null? + "nothing" : done.get(neigh))); + if(neigh == null || + done.get(neigh) != null) continue; + Flob nfl = f.findFlob(path, neigh); + p(" Found: "+nfl); + if(nfl != null) + p(" ...path: "+nfl.flobPath); + // show connections to non-shown cells + // XXX: is this tight-brick? if so, this should be + // made conditional + if(nfl == null) { + // XXX UseCorners!!! + int xo = xoffs[d]; + int yo = yoffs[d]; + int xh = (xo==0 ? 1 : 0); + int yh = (yo==0 ? 1 : 0); + int df = (dir > 0 ? 1 : 0); + int x1 = cur.x + ((2*xo + xh)*cur.w) / 2; + int y1 = cur.y + ((2*yo + yh)*cur.h) / 2; + int len = 1; // Stub length + int wid = 5; // Stub width + if (dir < 0) { + int cx = cur.x + cur.w / 2; + int cy = cur.y + cur.h / 2; + x1 = x1 - 2 * (x1 - cx) + dir*xo; + y1 = y1 - 2 * (y1 - cy) + dir*yo; + } + int x2 = x1 + dir * xo * len ; + int y2 = y1 + dir * yo * len ; + ldb.l(x1, y1, x2, y2); + ldb.l(x2+dir*yo*wid/2, y2-dir*xo*wid/2, + x2-dir*yo*wid/2, y2+dir*xo*wid/2); + continue; + } + + // Now, find line coordinates. + Flob from=null, to=null; + if(dir > 0) { + from = cur; to = nfl; + } else { + from = nfl; to = cur; + } + if(useCorners) { + int xo = xoffs[d]; + int yo = yoffs[d]; + int xh = (xo==0 ? 1 : 0); + int yh = (yo==0 ? 1 : 0); + ldb.l( + from.x + (2*xo + xh)*from.w / 2, + from.y + (2*yo + yh)*from.h / 2, + to.x + (xh)*to.w / 2, + to.y + (yh)*to.h / 2 + ); + } else { + from.getCenter(p1); + to.getCenter(p2); + // Check the direction. + // XXX abstract out! + int dx = p2.x - p1.x; + int dy = p2.y - p1.y; + boolean curve = false; + if(splines) { + if(d == 0) { // X + curve = (dx/(2*dy+1) == 0 || dx < 0); + } else if(d == 1) { // Y + curve = (dy/(2*dx+1) == 0 || dy < 0); + } else if(d == 2) { // Z + curve = ( + dx / (2*dy+1) != 0 || + dy / (2*dx+1) != 0 || + dx < 0 || + dy < 0 + ); + } + } + if(curve) { + p("SPLINE! "+d+" "+dx+" "+dy); + int aw = from.w + to.w; + int ah = from.h + to.h; + aw *= 2; + ah *= 2; + int[] curv = ZZUtil.bulgeCurve( + p1.x, p1.y, + xoffs[d] * aw, yoffs[d] * ah, + p2.x, p2.y, -xoffs[d] * aw, + -yoffs[d] * ah, + 9 + ); + for(int p=2; p= maxdepth) return new Vector(); + + ++currdepth; + + Vector rv = new Vector(); + + py("start"); + + if (root == null) { + py("root is null"); + } else { + py("root is " + root.getID()); + } + + // position a cell not in the tree that lies left from the root + ZZCell cell = root == null ? null : breadth.getCellPredecessor(root); + if (cell != null && !cellpos.containsKey(cell)) { + Dimension s = smcsize[currdepth]; + Dimension pos = new Dimension(); + pos.width = currbcoord; + pos.height = dcoord[currdepth] + + csize[currdepth].height / 2 - s.height / 2; + cellpos.put(cell, pos); + celldepth.put(cell, new Integer(maxdepth + 1)); + cellsize.put(cell, s); + extracells.put(cell, cell); + currbcoord += s.width + gaps[currdepth].width; + } + + if (root != null && cellpos.containsKey(root)) py("root is known"); + + int count = 0; + for (cell = root; + cell != null && (!cellpos.containsKey(cell) + || extracells.containsKey(cell)); + cell = breadth.getCellSuccessor(cell)) { + + if (extracells.containsKey(cell)) extracells.remove(cell); + + py("cell " + cell.getID()); + cellpos.put(cell, new Dimension()); + + rv.addElement(cell); + + int startbcoord = currbcoord; + Vector children = place_tree_cells(depth.getCellSuccessor(cell)); + int endbcoord = currbcoord; + + cellchildren.put(cell, children); + + Dimension cs = csize[currdepth]; + + int dcorr = 0; + // contain too many siblings so that + // eg. d.cellcreation as breadth does not hang; + // however, we must go on until the accursed cell is + // with us. + if (count > canvaswidth / csize[currdepth].width + && cellpos.containsKey(accursed) && cell != accursed) { + cs = smcsize[currdepth]; + dcorr = csize[currdepth].height / 2 - cs.height / 2; + extracells.put(cell, cell); + } + cellsize.put(cell, cs); + + Dimension cpos = new Dimension((startbcoord + endbcoord - cs.width) / 2, + dcoord[currdepth] + dcorr); + + if (cpos.width < startbcoord) cpos.width = startbcoord; + + py("positioning cell " + cell.getID() + " at (" + cpos.width + "," + cpos.height + ")"); + cellpos.put(cell, cpos); + celldepth.put(cell, new Integer(currdepth)); + if (currbcoord < cpos.width + cs.width + gaps[currdepth].width) + currbcoord = cpos.width + cs.width + gaps[currdepth].width; + + // position a cell not in the tree that lies up from the root + ZZCell up = depth.getCellPredecessor(cell); + if (up != null && !cellpos.containsKey(up)) { + Dimension s = smcsize[currdepth]; + Dimension pos = new Dimension(); + pos.width = cpos.width + csize[currdepth].width / 2 - s.width / 2; + pos.height = cpos.height - s.height - gaps[currdepth].width / 2; + cellpos.put(up, pos); + celldepth.put(up, new Integer(maxdepth + 1)); + cellsize.put(up, s); + extracells.put(up, up); + } + + if (extracells.containsKey(cell)) break; + count++; + } + py("finish"); + --currdepth; + return rv; + } + + public PositionDecider(DimVector breadth, DimVector depth, + Dimension fs, FlobFactory fact, + ZZCell accursed) { + this.breadth = breadth; + this.depth = depth; + this.canvaswidth = fs.width; + + this.accursed = accursed; + + py("created"); + + gaps = new Dimension[maxdepth]; + csize = new Dimension[maxdepth]; + smcsize = new Dimension[maxdepth]; + dcoord = new int[maxdepth]; + + gaps[maxdepth/2] = new Dimension(gap[0], gap[1]); + csize[maxdepth/2] = new Dimension(fact.getSize(null, initmul)); + if (depthhorizontal) { + int tmp = csize[maxdepth/2].width; + csize[maxdepth/2].width = csize[maxdepth/2].height; + csize[maxdepth/2].height = tmp; + } + dcoord[maxdepth/2] = (depthhorizontal ? fs.width : fs.height) / 2; + for (int i = maxdepth / 2 - 1; i >= 0; i--) { + gaps[i] = new Dimension((int)(gaps[i+1].width * shrink[0]), + (int)(gaps[i+1].height * shrink[1])); + csize[i] = new Dimension((int)(csize[i+1].width * shrink[0]), + (int)(csize[i+1].height * shrink[1])); + dcoord[i] = dcoord[i+1] - (csize[i+1].height + gaps[i+1].height); + } + for (int i = maxdepth / 2 + 1; i < maxdepth; i++) { + gaps[i] = gaps[maxdepth - 1 - i]; + csize[i] = csize[maxdepth - 1 - i]; + dcoord[i] = dcoord[i-1] + csize[i-1].height + gaps[i-1].height; + } + for (int i = 0; i < maxdepth; i++) { + smcsize[i] = new Dimension(csize[i].width / 4, + csize[i].height / 4); + } + + } + public Enumeration getCells() { return cellpos.keys(); } + public Dimension getCellPosition(ZZCell c) { + return new Dimension((Dimension)cellpos.get(c)); + } + public int getCellDepth(ZZCell c) { + return ((Integer) celldepth.get(c)).intValue(); + } + public Dimension getCellSize(ZZCell c) { + return new Dimension((Dimension)cellsize.get(c)); + } + + public boolean existCell(ZZCell c) { + return cellpos.containsKey(c); + } + + public Enumeration getCellChildren(ZZCell c) { + Object o = cellchildren.get(c); + Vector v; + if (o == null) v = new Vector(); else v = (Vector)o; + return v.elements(); + } + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + DimVector breadth = new DimVector(dims[0], 1); + DimVector depth = new DimVector(dims[1], 1); + + if (depthhorizontal) { + DimVector tmp = breadth; + breadth = depth; + depth = tmp; + } + + p("finding the root cell"); + ZZCell root; + { + ZZCell cell = accursed; + int count = 0; + Hashtable seen = new Hashtable(); + do { + root = cell; + seen.put(root, root); + cell = depth.getCellPredecessor(root); + boolean up = true; + if (cell == null) { + cell = breadth.getCellPredecessor(root); + up = false; + } + if (cell != null && seen.containsKey(cell)) cell = null; + if (cell != null && up) count++; + } while (cell != null && count < maxdepth / 2); + p("done finding the root cell"); + } + + PositionDecider pd = new PositionDecider(breadth, depth, + into.getSize(), + fact, accursed); + + pd.place_tree_cells(root); + + Dimension acpos; + if (pd.existCell(accursed)) { + acpos = pd.getCellPosition(accursed); + } else { + pa("FIXME: accursed cell not in modeled tree"); + acpos = into.getSize(); + acpos.width /= 2; + acpos.height /= 2; + } + + int bcorr = acpos.width - (depthhorizontal + ? into.getSize().height + : into.getSize().width) / 2; + + for (Enumeration e = pd.getCells(); e.hasMoreElements();) { + ZZCell cell = (ZZCell) e.nextElement(); + + Dimension pos = pd.getCellPosition(cell); + + pos.width -= bcorr; + + + if (depthhorizontal) { + int tmp = pos.width; + pos.width = pos.height; + pos.height = tmp; + } + + Dimension cs = pd.getCellSize(cell); + + if (depthhorizontal) { + int tmp = cs.width; + cs.width = cs.height; + cs.height = tmp; + } + + int d = pd.getCellDepth(cell); + + fact.makeFlob(into, cell, cell, 1, pos.width, pos.height, + d, cs.width, cs.height); + + // draw tree lines + if (treelines) { + for (Enumeration f = pd.getCellChildren(cell); + f.hasMoreElements();) { + ZZCell child = (ZZCell) f.nextElement(); + Dimension cpos = pd.getCellPosition(child); + cpos.width -= bcorr; + if (depthhorizontal) { + int tmp = cpos.width; + cpos.width = cpos.height; + cpos.height = tmp; + } + Dimension chs = pd.getCellSize(child); + if (depthhorizontal) { + int tmp = chs.width; + chs.width = chs.height; + chs.height = tmp; + } + if (depthhorizontal) { + into.add(new LineDecor(pos.width + cs.width, + pos.height + cs.height / 2, + cpos.width, + cpos.height + cs.height / 2, + Color.red, + (pd.getCellDepth(child) + d) / 2)); + } else { + into.add(new LineDecor(pos.width + cs.width / 2, + pos.height + cs.height, + cpos.width + chs.width / 2, + cpos.height, + Color.red, + (pd.getCellDepth(child) + d) / 2)); + } + } + } + + + } + + // XXX This should be a structparam later on. + (new StdLinks()).decorate(into, "", view); + + // Do the dimensions. XXX strings or cells? + if (true) { + Dimension s = fact.getSize(null, 1); + + ZZCell bdim = ZZCursorReal.get(view.s("d.dims", 1)); + ZZCell ddim = ZZCursorReal.get(view.s("d.dims", 1).s("d.dims", 1)); + + if (bdim == null || ddim == null) { + throw new ZZError("no dimensions"); + } + + Flob bfl = fact.makeFlob(into, bdim, bdim, 1, s.width, 0, + 1, s.width, s.height); + Flob dfl = fact.makeFlob(into, ddim, ddim, 1, 0, s.height, + 1, s.width, s.height); + bfl.flobPath = "dim"; + dfl.flobPath = "dim"; + + int wh = s.width / 2; + int hh = s.height / 2; + + into.add(new LineDecor(new int[] { wh, hh, wh, s.height, + wh, hh, s.width, hh }, + 8, Color.red, 1)); + } + } +} + +// vim: set syntax=java : diff --git a/Java/flob/VanishingView.zob b/Java/flob/VanishingView.zob new file mode 100644 index 0000000..e6e8787 --- /dev/null +++ b/Java/flob/VanishingView.zob @@ -0,0 +1,317 @@ +/* +VanishingView.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A reimplementation of the vanishing raster. + * Much simpler than the original one since this one does not try + * to do the hard rasters as well. + */ + +public class VanishingView implements FlobView, ZOb { +public static final String rcsid = "$Id: VanishingView.zob,v 1.9 2000/12/11 02:54:44 tjl Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + // Following are the parameters out of which the constructor + // is created. + + STRUCTPARAMS { + + /** The factor to shrink the cells with when moving away from + * center. + */ + float[] shrink // 2..2 + = new float[] {(float)0.9, (float)0.9}; + + /** The factor the center cell is enlarged with from default. + */ + float[] initmul // 2..2 + = new float[] {(float)1.6, (float)1.6}; + + /** The factor to enlarge the center cell on top of initmul. + * This only has an effect on the center cell whereas initmul + * affects all cells. + */ + float[] centermul // 2..2 + = new float[] {(float)1.0, (float)1.0}; + + /** The distance between neighbouring cells. + */ + int[] gap // 2..2 + = new int[] {5, 5}; + + /** The depth to raster to. + */ + int depth + = 5; + + /** The precedence order of dimensions. + */ + int[] pref // 2..5 + = new int[] {0, 1, 2}; + + /** Whether to allow cell sizes to vary. + */ + boolean varsize + = false; + + /** Whether alignment around visual flob center is to be used. + * If true, halign is ignored. + */ + boolean centeralign + = true; + + /** Distance reverse perspective. + */ + float revper + = (float)1.00; + + /** Horizontal alignment. + * 0 = center, -1 = left, 1 = right. + */ + int halign + = 0; + } + + // XXX This should be a structparam later on. + FlobDecorator linker = new StdLinks(); + + + // Offsets of x and y + static int[] xoffs = new int[] {1, 0, 1}; + static int[] yoffs = new int[] {0, 1, 1}; + + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + Dimension fs = into.getSize(); + + // Precalculate sizes and gaps. + int[] xgap = new int[depth]; + int[] ygap = new int[depth]; + + int[] xsize = new int[depth+1]; + int[] ysize = new int[depth+1]; + float[] sizfact = new float[depth+1]; + + float xf = initmul[0]; + float yf = initmul[1]; + Dimension d0 = fact.getSize(null, yf); + Dimension d = (varsize ? fact.getSize(accursed, yf) : d0); + + xsize[0] = d.width; + ysize[0] = d.height; + sizfact[0] = yf; + float yf0 = yf, xf0=xf; + + for(int i=0; i= maxd) continue; + if(did[dim].get(curFlob[0].c) != null) continue; + did[dim].put(curFlob[0].c, curFlob[0].c); + + // Current depth + int curd = (curFlob[0].d - d1) / dm; + + ZZIter.NEnum rank = ZZIter.alternate(curFlob[0].c, false, dims[pref[dim]], 1); + ZZCell next; + while((next = rank.nextCell()) != null) { + int curind = (rank.nth() < 0 ? 0 : 1); + int dir = curind * 2 - 1; + int xdep = (rank.nth() < 0 ? -rank.nth() : rank.nth()); + Flob f = curFlob[curind]; + + if(cellsDone.get(next) != null || + curd + xdep >= depth) { + rank.stop(); + continue; + } + + cellsDone.put(next, next); + + if(centeralign) { + + // First, determine alignment. + int xalign = dir * xoffs[pref[dim]]; + int yalign = dir * yoffs[pref[dim]]; + + // Then, find alignment point in last cell, + // centered on center of screen + f.getPoint(aligned, xalign, yalign); + + // Using that, find alignment point + // in the next cell. + + aligned.x -= fs.width / 2; + aligned.x *= revper; + aligned.x += fs.width / 2; + + aligned.y -= fs.height / 2; + aligned.y *= revper; + aligned.y += fs.height / 2; + + aligned.x += xalign*xgap[curd+xdep-1]; + aligned.y += yalign*ygap[curd+xdep-1]; + + Dimension size = new Dimension(xsize[curd+xdep], + ysize[curd+xdep]); + f = curFlob[curind] = fact.centerFlob(into, next, next, + sizfact[curd+xdep], aligned, -xalign, -yalign, + d1 + dm * (curd + xdep), varsize ? null : size); + + } else { + + int x=0, y=0, w=0, h=0; + if(varsize) { + Dimension dvar = fact.getSize(next, sizfact[curd+xdep]); + w = dvar.width; + h = dvar.height; + } else { + w = xsize[curd+xdep]; + h = ysize[curd+xdep]; + } + + // A bit tricky due to flob coords being + // UL corner. + + // First, find alignment point in last cell, + // centered on center of screen + int alignedX = + f.x + (halign+1)*f.w/2 - fs.width/2; + int alignedY = + f.y + f.h/2 - fs.height/2; + + // Then, using that, find alignment point + // in the next cell. + int xof = xoffs[pref[dim]]; + alignedX += dir * xof * ( + xgap[curd+xdep-1] + (1-dir*halign) * f.w/2 + + (1+dir*halign) * w/2 + ); + alignedY += dir * yoffs[pref[dim]] * ( + ygap[curd+xdep-1] + f.h/2 + h/2 + ); + + // Expand the coordinate system around the + // origin + alignedX *= revper; + alignedY *= revper; + + // Finally, find upper left corner of next cell. + x = alignedX - (halign+1)*w/2 + fs.width/2; + y = alignedY - h/2 + fs.height/2; + + p("Vanishing: puttig "+next+ + x+" "+y+" "+w+" "+h); + + f = curFlob[curind] = fact.makeFlob(into, next, next, + sizfact[curd+xdep], x, y, + d1 + dm * (curd + xdep), w, h); + + } + + cur.addElement(f); + did[dim].put(f.c, f.c); + added = true; + } + } + // If we added cells, and we're not doing a hard + // raster, start doing dimensions all over again. + if(added) dim = -1; + } + + linker.decorate(into, "", view); + + // Do the dimensions. + if(true) + ZZUtil.showFlobDims(into, fact, view, 3); + } + +} + + +// vim: set syntax=java : diff --git a/Java/flob/VobSet.java b/Java/flob/VobSet.java new file mode 100644 index 0000000..15c06ab --- /dev/null +++ b/Java/flob/VobSet.java @@ -0,0 +1,73 @@ +/* +VobSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A draft for a new interface to FlobSet. + * The point is that this interface can be implemented by several + * things and we can make dfferent views interact in interesting + * ways. + *

    + * A VobSet can be thought of as a window in some ways... + */ + +abstract public class VobSet implements ZZScene { +public static final String rcsid = "$Id: VobSet.java,v 1.1 2000/12/11 02:54:10 tjl Exp $"; + + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + abstract public Rectangle getBounds(); + abstract public int getDepth(); + + // XXX Make it use ZZDrawing2D to get the bg paint. + abstract public Color getBackground(); + + abstract public void add(Renderable r); + abstract public void add(Flob f); + + // ??? protected void depthColor(Graphics g, int depth) { + + abstract public void dump(); + + /** A callback interface for iterating over the Flobs + * in a FlobSet in depth order. + */ + public interface DepthIter { + void act(Flob[] flobs, int start, int n); + } + + /** Iterate a routine over a blocks of same-depth flobs. + */ + abstract public void iterDepth(DepthIter di, boolean frontFirst); + + + + // XXX Spanset? + // abstract public SpanFlob[] findFlobs(Span s); + + // abstract public + +} diff --git a/Java/flob/WindowCellView.zob b/Java/flob/WindowCellView.zob new file mode 100644 index 0000000..c7b016e --- /dev/null +++ b/Java/flob/WindowCellView.zob @@ -0,0 +1,129 @@ +/* +ClockCellView.zob + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * Copyright (c) 2001, Benja Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benja Fallenstein + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A cell view that shows the contents of a window. + * Use this ZOb as the headcell on d.cellview from the window's cursor cell, + * and that cell will appear as the window's contents. + */ + +public class WindowCellView implements FlobFactory, ZOb { +public static final String rcsid = "$Id: WindowCellView.zob,v 1.3 2001/03/18 17:50:16 bfallenstein Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + STRUCTPARAMS { + } + + public Dimension getSize(ZZCell c, float fract) { + // XXX use the bounds as specified in the structure + return new Dimension((int)(500*fract), (int)(300*fract)); + } + + public Flob makeFlob(FlobSet into, ZZCell c0, ZZCell handleCell, + float fract, + int x, int y, int d, int w, int h) { + + FlobSet sc = into.create(new Dimension(w, h)); + SceneFlob sf = new SimpleSceneFlob(x, y, d, w, h, c0, sc); + CellFlobFactory1.addSolidColors(into, sf, sf); + into.add(sf); + + if(w+h < 100) return sf; + ZZCell view = c0.getRootclone(); + + ZZCell c = ZZDefaultSpace.findInheritableParam(view, "View"); + ZZCell rastname = ZZCursorReal.get(c); + + ZOb frz = ZZDefaultSpace.readZOb(rastname); + FlobView fr = null; + if(frz != null && frz instanceof FlobView) { + fr = (FlobView)frz ; + } else { + System.out.println("getScene: invalid type: "+frz); + fr = new NullView(); + } + // XXX Signal error + + c = ZZDefaultSpace.findInheritableParam(view, "CellView"); + + FlobFactory rff = null; + if(c != null) { + ZZCell cfact = ZZCursorReal.get(c); + + ZOb ffzob = ZZDefaultSpace.readZOb(cfact); + rff = (FlobFactory) ffzob; + } + + p("WindowCellView: prepare view"); + fr.raster(sc, rff, view, ZZDefaultSpace.getDimList(view), + ZZCursorReal.get(view)); + p("WindowCellView: view prepared"); + + if(rff != null) { + Flob rn = rff.placeFlob(sc, rastname, rastname, (float)1.5, w, 0, 1, 1, 0); + rn.flobPath="rastname"; + } + + return sf; + } + + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract) { + Dimension d = getSize(c, fract); + return makeFlob(into, c, handleCell, fract, + (int)(x-xfract*d.width), + (int)(y-yfract*d.height), + depth, d.width, d.height); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d) { + if(d == null) d = getSize(c, fract); + int x, y; + x = p.x - d.width/2; y = p.y - d.height/2; + + if(xalign < 0) x = p.x; + if(xalign > 0) x = p.x - d.width; + if(yalign < 0) y = p.y; + if(yalign > 0) y = p.y - d.height; + p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign); + return makeFlob(into, c, handleCell, fract, x, y, + depth, d.width, d.height); + } + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) { + return centerFlob(into, c, handleCell, fract, p, xalign, yalign, + depth, null); + } +} + +// vim: set syntax=java : diff --git a/Java/media/Address.java b/Java/media/Address.java new file mode 100644 index 0000000..ac3f06e --- /dev/null +++ b/Java/media/Address.java @@ -0,0 +1,95 @@ +/* +Address.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.util.*; + +/** An address in a stable media stream. + * Currently just a silly pointer but will be later extended + * to include full tumblers. + * Format: streamid.offset, where streamid is an alphanumeric string + * identifying a stream. + */ + +public class Address { +public static final String rcsid = "$Id: Address.java,v 1.3 2000/09/19 10:32:00 ajk Exp $"; + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + Scroll scroll; + String stream; + long offset; + public static Address parse(String s) { + StringTokenizer st = new StringTokenizer(s, "."); + if(st.countTokens() != 2) { + throw new ZZError("Wrong number of toks in '"+s+"'"); + } + Address a = new Address(); + a.stream = st.nextToken(); + a.offset = Long.parseLong(st.nextToken()); + return a; + } + + public static Address streamOffs(String s, long offs) { + Address a = new Address(); + a.stream = s; + a.offset = offs; + return a; + } + public static Address scrollOffs(Scroll s, long offs) { + // return s.getId() + "." + offs; + Address a = new Address(); + a.stream = s.getId(); + a.offset = offs; + return a; + } + + public String getStream() { return stream; } + public Scroll getScroll(ZZSpace s) { + if(scroll==null) scroll = Scroll.obtain(s, stream); + return scroll; + } + public long getOffs() { return offset; } + + public String toString() { + return stream.toString() + "." + offset; + } + + public boolean lessThan(Address a) { + int c = stream.compareTo(a.stream); + if(c < 0) return true; + if(c > 0) return false; + if(offset < a.offset) return true; + return false; + } + + public Address addOffs(int o) { + Address a = new Address(); + a.scroll = scroll; + a.stream = stream; + a.offset = offset + o; + return a; + } + +} + diff --git a/Java/media/ByteScroll.java b/Java/media/ByteScroll.java new file mode 100644 index 0000000..9d80698 --- /dev/null +++ b/Java/media/ByteScroll.java @@ -0,0 +1,99 @@ +/* +ByteScroll.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A scroll of bytes. May later have holes etc. from expunging, + * but basically the point is that the address to content mapping + * is stable and will not change whatever is done. + */ +public class ByteScroll extends Scroll{ +public static final String rcsid = "$Id: ByteScroll.java,v 1.4 2000/09/19 10:32:00 ajk Exp $"; + // Cheat: it's just a file + private RandomAccessFile f; + + private String encoding; + + private boolean readonly; + + public ByteScroll(String id, File fn, String mode, String encoding, + boolean ro) { + super(id); + this.encoding = encoding; + this.readonly = ro; + try { + f = new RandomAccessFile(fn, mode); + } catch(Exception e) { + ZZLogger.exc(e); + throw new NullPointerException("Can't get"); + } + } + + public synchronized byte[] get(long start, int n) { + try { + f.seek(start); + byte[] ret = new byte[n]; + int r = f.read(ret); + if(r!=n) + throw new NullPointerException("NOT ENOUGH!"); + return ret; + } catch(Exception e) { + ZZLogger.exc(e); + throw new NullPointerException("Can't get"); + } + } + + // XXX ENCODING + public String getString(long start, int n) { + byte[] b = get(start,n); + try { + return new String(b, "ISO8859_1"); + } catch(Exception e) { + ZZLogger.exc(e); + throw new NullPointerException("Can't get"); + } + } + + public long curEnd() { try { return f.length(); + } catch(Exception e) { + ZZLogger.exc(e); + throw new NullPointerException("Can't get"); + } + } + + public synchronized long append(byte[] bytes) { + if(readonly) throw new ZZError("Can't append to readonly scroll"); + try { + long offs = curEnd(); + f.seek(offs); + f.write(bytes); + return offs; + } catch(Exception e) { + ZZLogger.exc(e); + throw new NullPointerException("Can't get"); + } + } +} + + diff --git a/Java/media/Capitalizer.java b/Java/media/Capitalizer.java new file mode 100644 index 0000000..51e8c7d --- /dev/null +++ b/Java/media/Capitalizer.java @@ -0,0 +1,100 @@ +/* +Capitalizer.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Capitalizing code written by Tuomas Lukka + */ + +package org.gzigzag; +import java.awt.*; +import java.util.*; + +/** A class to capitalize first letters of sentences. + * A sentence is separated by two or more spaces. If you just need to + * capitalize one string, use the static method single(String). If you need + * to capitalize a number of concurrent strings, instantiate Capitalizer and + * run cap(String) over them, in order. + *

    + * The algorithm is tricky and probably needs a lot of adjustment. + * The first letters of sentences are currently identified by + * two spaces next to each other. + */ + +public class Capitalizer { +public static final String rcsid = "$Id: Capitalizer.java,v 1.1 2000/12/25 19:37:09 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + /** Have we read a single space? */ + boolean hadSpace = false; + + /** Are we past a sentence boundary (two spaces)? */ + boolean boundary = true; + + public static String single(String s) { + return new Capitalizer().cap(s); + } + + public String cap(String s) { + int len = s.length(); + // Look for the first non-space character the hard way. + int i; + for(i=0; i 1) { + char c1 = s.charAt(len-1); + if(c1 == ' ') { + char c2 = s.charAt(len-2); + boundary = (c2 == ' '); + hadSpace = (c2 != ' '); + } + } + // Then, find the other occurrences. + int ind = i-1; + while((ind = s.indexOf(" ", ind+1)) >= 0) { + if(ind == s.length() - 2) break; + if(Character.isLetter(s.charAt(ind+2))) + s = s.substring(0, ind+2) + + Character.toUpperCase( s.charAt(ind+2)) + + s.substring(ind+3); + } + return s; + } +} \ No newline at end of file diff --git a/Java/media/CharScroll.java b/Java/media/CharScroll.java new file mode 100644 index 0000000..e5b03ae --- /dev/null +++ b/Java/media/CharScroll.java @@ -0,0 +1,109 @@ +/* +CharScroll.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** DEPRECATED FOR STRINGSCROLL + * A scroll of chars. May later have holes etc. from expunging, + * but basically the point is that the address to content mapping + * is stable and will not change whatever is done. + * XXX copied from ByteScroll - sad. + */ +public class CharScroll extends Scroll{ +public static final String rcsid = "$Id: CharScroll.java,v 1.5 2000/09/19 10:32:00 ajk Exp $"; + // Cheat: it's just a file + private RandomAccessFile f; + // public static final boolean dbg = true; + // static final void p(String s) { if(dbg) System.out.println(s); } + + + private boolean readonly; + + public CharScroll(String id, File fn, String mode, + boolean ro) { + super(id); + this.readonly = ro; + try { + f = new RandomAccessFile(fn, mode); + } catch(Exception e) { + ZZLogger.exc(e); + throw new NullPointerException("Can't get"); + } + } + + public synchronized char[] get(long start, int n) { + try { + f.seek(start*2); + byte[] ret = new byte[n*2]; + int r = f.read(ret); + if(r!=n*2) + throw new NullPointerException("NOT ENOUGH!"); + char[] c = new char[n]; + for(int i=0; i res) res = h; + } + return res; + } + public static int len(Part[] ps) { + int res = 0; + for(int i=0; i= at) { + return new int[] { i, p.n-(here-at) }; + } + } + return new int[] { parts.length-1, parts[parts.length-1].n }; + } + + /** Return lines laid out at a given width. + * The dimensions of the array are lines[line][part] + */ + public Part[][] getLines(int width) { + return FirstMatchBreaker.stupidBreak(this, width); + } + + public static int findLine(Part[][] lines, int offs) { + int here = 0; + for(int i=0; i= offs) return i; + } + return lines.length-1; + } + + /** Capitalize the sentences in the whole FText. */ + public void capitalize() { + Capitalizer c = new Capitalizer(); + for(int i=0; i= 0) { + char c = s.charAt(here); + v.addElement(new Word(p, last+1, here+1, c == '\n')); + last = here; + } + v.addElement(new Word(p, last+1, s.length(), false)); + } + + return v; + } + + /** Internal convenience: Vector to array. */ + private static FText.Part[] v2a(Vector v) { + concat(v); + FText.Part[] res = new FText.Part[v.size()]; + for(int i=0; i linestart && x > width) { + lineset.addElement(v2a(line)); + line.removeAllElements(); + x = w.width(); linestart = i; + } + line.addElement(w); + if(x > width || w.forced) { + /* w alone doesn't fit on our line, or forced break after w */ + lineset.addElement(v2a(line)); + line.removeAllElements(); + x = 0; linestart = i+1; + } + } + if(line.size() > 0) lineset.addElement(v2a(line)); + FText.Part[][] res = new FText.Part[lineset.size()][]; + for(int j=0; j + * Specific attention is paid to the billowing problem where + * we have to render a paragraph so that the cursor is at the line with + * the first line of the paragraph starts from the beginning of a line. + * This is achieved by specifying the cursor position (from where the lines + * should be counted) and the desired line number for that position. + * This can also be used to render the paragraph starting from the end. + */ + +public abstract class LineBreaker { +String rcsid = "$Id: LineBreaker.java,v 1.8.10.1 2001/08/16 13:50:01 bfallenstein Exp $"; + static private void pa(String s) { System.out.println(s); } + /** Break the lines between the given addresses. + * @return An array: the first element is the line index the rendering + * starts on, and from the second element onwards the end points of the + * lines are given. + */ + public abstract int[] breakLines(LineInfo li); + + static private void test(LineBreaker b, String str, int cursor, + SimpleLineInfo.Layout l) { + SimpleLineInfo inf = new SimpleLineInfo(str, cursor, l); + int[] foo = b.breakLines(inf); + pa("Tested '"+str+"'"); + for(int i=0; i= cur && xc <= cur+lenn) { + p("Cursor was on this line"); + // We hit the cursor here. + if(line > l) { + // line greater -> move upwards. This is a maximum. + startmax = curstart; gotmax = true; + curstart -= (line - l); + } else if(line < l) { + // line smaller -> move down. This is a min. + startmin = curstart; gotmin = true; + curstart += (l - line); + } + if(line == l) ret = true; + } + res.addElement(new Integer(cur + lenn)); + line ++; + } + + if(gotmin && gotmax && startmax - startmin < 2) { + ret = true; + curstart = startmin; + } else { + if(gotmin && curstart <= startmin) { + curstart = startmin + 1; + } + if(gotmax && curstart >= startmax) { + curstart = startmax - 1; + } + } + + p("Ret: curstart = "+curstart); + + if(ret) { + int[] r = new int[res.size() + 1]; + r[0] = curstart; + for(int i=1; i 1000) { + p("Too wide"); + maxn = guessn; + li.split(x0, guessn, x0+(guessn*1000/res[0]), res); + p("Split res: "+guessn+" "+res[0]+" "+minn); + if(guessn == res[0] || minn == guessn) return best; + guessn = res[0]; + splitpen = res[1]; + } else { + p("Too narrow"); + minn = guessn; + li.split(x0+guessn, maxn-guessn, + x0+guessn+ + ((1000000/(res[0]+1) - 1000) * (maxn-guessn))/1000, + res); + res[0] += guessn; + if(guessn == res[0] || maxn == guessn) return best; + guessn = res[0]; + splitpen = res[1]; + } + if(minn >= maxn || guessn <= minn || guessn >= maxn) return best;; + } + } + + +} diff --git a/Java/media/SimpleLineInfo.java b/Java/media/SimpleLineInfo.java new file mode 100644 index 0000000..f5b01e2 --- /dev/null +++ b/Java/media/SimpleLineInfo.java @@ -0,0 +1,91 @@ +/* +SimpleLineInfo.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; +import java.awt.*; + +/** A simple implementation of LineInfo, for plain strings in a list + * of fonts. + */ + +public class SimpleLineInfo implements LineInfo { +public static final String rcsid = "$Id: SimpleLineInfo.java,v 1.8 2000/09/19 10:32:00 ajk Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + public interface Layout { + FontMetrics getFontMetrics(int line); + int getWidth(int line); + int getCenterLine(); + } + + String s; + Layout l; + int cursor; + + SimpleLineInfo(String s, int cursor, Layout l) { this.s = s; this.l = l; + this.cursor = cursor;} + + public int getMax() { return s.length(); } + public int getCursor() { return cursor; } + public int getCenterLine() { return l.getCenterLine(); } + + public void split(int x0, int n, int sug, int[] ret) { + int ind = s.indexOf(' ', x0+1); + + if(ind >= x0+n || ind < 0) { + // split word + ind = 1; + ret[0] = 1; + ret[1] = 500; + } else { + while(true) { + int ind2 = s.indexOf(' ', ind+1); + if(ind2 < 0) break; + if(ind2 >= x0+n) break; + if(ind2 >= sug) break; + ind = ind2; + } + ret[0] = ind - x0; + ret[1] = 0; + } + p("Split: "+x0+" "+n+" "+sug+" "+ret[0]+" "+ret[1]); + } + + public void widthPenalty(int x0, int n, int line, int[] ret) { + p("WP: "+x0+" "+n+" "+line); + String subs = s.substring(x0, x0+n).trim(); + int w = l.getFontMetrics(line).stringWidth(subs); + int want = l.getWidth(line); + ret[0] = (1000*w) / want; + if(w > want) { + ret[1] = (w-want) * (w-want) / 3; + } else { + ret[1] = (want - w) / 2; + } + p("WP: "+x0+" "+n+" "+line+" "+want+" "+w+" Ret: "+ret[0]+" "+ret[1]); + } +} + + diff --git a/Java/media/SoundScroll.java b/Java/media/SoundScroll.java new file mode 100644 index 0000000..146f93b --- /dev/null +++ b/Java/media/SoundScroll.java @@ -0,0 +1,63 @@ +/* +SoundScroll.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.io.*; +import java.util.*; + +/** A scroll of sound. + * The fact that you need to specify the duraction when creating is not good but + * we can fix that later somehow. + */ +public class SoundScroll extends Scroll { +public static final String rcsid = "$Id: SoundScroll.java,v 1.3 2000/09/19 10:32:00 ajk Exp $"; + + // public abstract void preparePlayer(); + /** XXX change to play(Span) and get the next at runtime? + */ + protected SoundScroll(String i) { super(i); } + + Vector obses = new Vector(); + public void addObs(SoundObs o) { + obses.addElement(o); + } + protected void inform(int event, long l) { + for(int i = 0; i + * Spans are immutable, just like Strings: all the verb-like method + * like join and split return new Span objects. + */ + +public class Span { +public static final String rcsid = "$Id: Span.java,v 1.9 2001/03/11 19:14:38 veparkki Exp $"; + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + Address a1; + Address a2; + + public Address getStart() { return a1; } + public Address getEnd() { return a2; } + public long getStartOffs() { return a1.offset; } + public long getEndOffs() { return a2.offset; } + + public static Span parse(String str) { + StringTokenizer st = new StringTokenizer(str, ":"); + if(st.countTokens() != 2) + throw new ZZError("Wrong number of ':' toks in '"+str+"'"); + Span s = new Span(); + s.a1 = Address.parse(st.nextToken()); + s.a2 = Address.parse(st.nextToken()); + if(!s.a1.getStream().equals(s.a2.getStream())) + throw new ZZError("Must be same stream for now '" + str + +"' '"+s.a1.getStream()+"' '"+s.a2.getStream()+"'"); + return s; + } + + public static Span create(Address i1, Address i2) { + Span s = new Span(); + s.a1 = i1; s.a2 = i2; + return s; + } + + public String toString() { + return a1+":"+a2; + } + + public boolean overlaps(Span s) { + if(a2.lessThan(s.a1) || s.a2.lessThan(a1)) return false; + return true; + } + + /** The string pointed to by the span. + */ + public String getString(ZZCell c) { + Scroll scr //= c.getSpace().getStringScroll(a1.getStream()); + = Scroll.obtain((c==null?null:c.getSpace()), + a1.getStream()); + p("Scroll: "+scr); + if(scr instanceof StringScroll) { + StringScroll s = (StringScroll) scr; + int o1 = (int)a1.getOffs(); + int o2 = (int)a2.getOffs(); + if(o1 > o2) { + // This is allowed + if(o1-o2 == 1) return ""; + // This is not + throw new ZZError("Too negative span "+ this); + } + return s.getString(a1.getOffs(), + (int)(o2-o1)+1); + } if(scr instanceof ByteScroll) { + ByteScroll s = (ByteScroll)scr; + return s.getString(a1.getOffs(), + (int)(a2.getOffs()-a1.getOffs())+1); + } + if(scr instanceof CharScroll) { + CharScroll s = (CharScroll)scr; + return s.getString(a1.getOffs(), + (int)(a2.getOffs()-a1.getOffs())+1); + } + if(scr instanceof SoundScroll) { + return "SND " + toString(); + } + return "???"; + } + + public Span adjustEdge(int edge, long units) { + Address adj = (edge==0?a1:a2); + adj = Address.streamOffs(adj.getStream(), adj.getOffs()+units); + Address x = (edge==0?adj:a1); + Address y = (edge==1?adj:a2); + return create(x,y); + } + public Span[] adjustEdgeLocked(long units, Span other, long allowfudge) { + Address adj = a2; + adj = Address.streamOffs(adj.getStream(), adj.getOffs()+units); + long d = adj.getOffs() - other.a1.getOffs(); + if(d<0) d = -d; + if(d>allowfudge) + return new Span[] { + create(a1, adj), other + }; + return new Span[] { + create(a1, adj), + create(Address.streamOffs(adj.getStream(), adj.getOffs()+1), + other.a2) + }; + + } + public Span[] splitInHalf() { + long off = (a1.getOffs() + a2.getOffs()) / 2; + return new Span[] { + create(a1, Address.streamOffs(a1.getStream(), off-1)), + create(Address.streamOffs(a1.getStream(), off), a2), + }; + } + public Span join(Span next, long allowfudge) { + if(! a2.getStream().equals(next.a1.getStream())) + return null; + long diff = a2.getOffs() - next.a1.getOffs(); + if(diff<0) diff = -diff; + if(diff > allowfudge) + return null; + return create(a1, next.a2); + } + + /** Does exactly what substring does to String. + * This is in opposition to the other span routines + * in which the last address is given, not one beyond! + */ + public Span subSpan(int o1, int o2) { + return create(a1.addOffs(o1), a1.addOffs(o2-1)); + } + public Span subSpan(int o1) { + return create(a1.addOffs(o1), a2); + } + + /** Whether this span can be joined with the other span. + */ + public boolean isAppendable(Span s) { + return a2.getStream().equals(s.a1.getStream()) + && a2.getOffs() == s.a1.getOffs()-1; + } + + // XXX Check? + public Span append(Span s) { + return create(a1, s.a2); + } + + + public long length() { + return a2.getOffs() - a1.getOffs() + 1; + } + +} diff --git a/Java/media/SpanSet.java b/Java/media/SpanSet.java new file mode 100644 index 0000000..bc59749 --- /dev/null +++ b/Java/media/SpanSet.java @@ -0,0 +1,45 @@ +/* +SpanSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** An interface to Flobs that contain spans. This is more a Map than + * a Set... + * XXX Extend with links, i.e. one-level indirection between + * overlaps. + */ + +public interface SpanSet { +String rcsid = "$Id: SpanSet.java,v 1.4 2000/09/19 10:32:00 ajk Exp $"; + /** Add a span. + */ + void addSpan(Span s, Object obj); + /** Get the objects corresponding to the spans entered that overlap + * the given span. XXX Should be enumeration? + */ + Object[] overlaps(Span s); +} + + + diff --git a/Java/media/SpanTree.java b/Java/media/SpanTree.java new file mode 100644 index 0000000..6e9cf49 --- /dev/null +++ b/Java/media/SpanTree.java @@ -0,0 +1,54 @@ +/* +SpanTree.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.util.*; + +/** A structure for putting spans in and obtaining the + * matching spans. Not actually a tree yet XXX! + */ + +public class SpanTree implements SpanSet { +public static final String rcsid = "$Id: SpanTree.java,v 1.4 2000/09/19 10:32:00 ajk Exp $"; + Vector v = new Vector(); + Vector vo = new Vector(); + public void addSpan(Span s, Object uo) { + v.addElement(s); + vo.addElement(uo); + } + public Object[] overlaps(Span s) { + Vector res = new Vector(); + int ind = 0; + for(Enumeration e = v.elements(); e.hasMoreElements();) { + Span s0 = (Span)e.nextElement(); + if(s.overlaps(s0)) { + res.addElement(vo.elementAt(ind)); + } + ind++; + } + Object[] r = new Object[res.size()]; + for(int i=0; i nc.getText().length() - + (lookingDir > 0 ? 1 : 0)) { + o -= nc.getText().length(); + prev = nc; + nc = nc.s(dim); + } + if(nc == null) { + if(o != 0) + return false; + else { + nc = prev; + o = nc.getText().length(); + } + } + if(o < 0) + throw new ZZError("WHAT? WHAT? WHAT? Neg offset in move"); + curs.set(nc); curs.setOffs(o); + return true; + } + + /** Find a position along a stream with the given string. + * Currently relatively inefficient, unless the cells are relatively + * long. + */ + static public boolean find(ZZCursor from, String dim, int dir, + boolean includeThis, String text) { + // First, see if there is a match inside the current cell, + // done carefully. + ZZCell c = from.get(); + int offs = from.getOffs(); + + p("Find: "+c+" "+offs+" "+dim+" "+dir+" "+includeThis+" '"+text+"'"); + + String txt = c.getText(); + char first = text.charAt(0); + + if(!includeThis) offs += dir; + + if(dir > 0) { + while(c != null) { + while((offs = txt.indexOf(first, offs)) >= 0) { + if(isMatch(c, offs, text, dim, from)) + return true; + offs ++; + } + c = c.s(dim, dir); + if(c != null) { + txt = c.getText(); + offs = 0; + } + } + } else { + while(c != null) { + p("Findnegloop: "+c); + while((offs = txt.lastIndexOf(first, offs)) >= 0) { + p("Findnegloop: try "+ offs); + if(isMatch(c, offs, text, dim, from)) + return true; + offs --; + } + c = c.s(dim, dir); + if(c != null) { + txt = c.getText(); + offs = txt.length()-1; + } + } + } + + p("Not found!"); + + // Then, we're looking at whole cells the rest of the way. + return false; + } + + /** Check to see whether the text in the stream is equal to this text. + */ + static public boolean isMatch(ZZCell c, int offs, String text, String dim) { + return isMatch(c, offs, text, dim, null); + } + + /** Check whether the match is correct and set the cursor if it is. + */ + static boolean isMatch(ZZCell c, int offs, String text, + String dim, ZZCursor from) + { + p("Match: "+c+" "+offs+" '"+text+"' "+dim); + p("Matching csubstr: '"+c.getText().substring(offs)+"'"); + ZZCell origc = c; + int origoffs = offs; + while(c != null) { + String ct = c.getText().substring(offs); + if(ct.length() >= text.length()) { + if(ct.substring(0, text.length()).equals(text)) { + if(from != null) { + from.set(origc); + from.setOffs(origoffs); + } + p("TRUE!"); + return true; + } else return false; + } + if(!text.substring(0, ct.length()).equals(ct)) return false; + text = text.substring(ct.length()); + c = c.s(dim); + offs = 0; + } + return false; + } + + static public String getString(ZZCursor curs, String dim, int n) { + ZZCell c = curs.get(); + int offs = curs.getOffs(); + StringBuffer res = new StringBuffer(); + while(n > 0) { + String txt = c.getText(); + if(offs > 0) txt = txt.substring(offs); + if(n <= txt.length()) { + res.append(txt.substring(0, n)); + return res.toString(); + } + res.append(txt); + n -= txt.length(); + offs = 0; + c = c.s(dim); + if(c == null) return null; + } + return null; + } + + /** A class for moving along the stream, collecting characters. + * Part of the interface might be abstracted to an interface like + * java.text.CharacterIterator, but in a slightly more restricted subset. + *

    + * This class considers the end of the stream the location when it + * can't return any characters any more + 1. + */ + static public class Iterator { + final ZZCursorVirtual c; + final String dim; + + Iterator(ZZCursorVirtual c, String dim) { this.c = c; this.dim = dim; } + + public void set(ZZCursor c) { this.c.set(c); } + + /** Get the current iterator position. + * @return The current position. The position should not be modified. + */ + public ZZCursor get() { return c; } + + public boolean move(int nsteps) { + if(!Stream.move(c, dim, nsteps)) return false; + if(c.get().s(dim) == null) + // XXX Is this right? + if(c.get().getText().length() <= c.getOffs()) + return false; + return true; + } + + public boolean move(int nsteps, int lookingDir) { + if(!Stream.move(c, dim, nsteps, lookingDir)) return false; + if(c.get().s(dim) == null) + if(c.get().getText().length() <= c.getOffs()) + return false; + return true; + } + + public void start() { + c.set(c.get().h(dim)); + c.setOffs(0); + } + + public void end() { + ZZCell cl = c.get().h(dim, 1); + c.set(cl); + c.setOffs(cl.getText().length()); + } + + public void end(int dir) { + if(dir < 0) start(); else end(); + } + + public boolean find(int dir, boolean includeThis, String text) { + return Stream.find(c, dim, dir, includeThis, text); + } + + /** Get the current character. + * Returns -1 for the end-of-stream. + */ + public char getChar() { + return getChar(0); + } + + public char getChar(int offs) { + ZZCursorVirtual c1 = new ZZCursorVirtual(c); + // Move even if zero, to get the right + // directional position. + if(!Stream.move(c1, dim, offs, 1)) return (char)-1; + String str = c1.get().getText(); + if(c1.getOffs() >= str.length()) return (char)-1; + return str.charAt(c1.getOffs()); + } + + public String getString(int n, int dir) { + // SLOW!!!! + ZZCursorVirtual c1 = new ZZCursorVirtual(c); + if(dir < 0) { + if(!Stream.move(c1, dim, -n)) return null; + } + return Stream.getString(c1, dim, n); + } + } + + static public Iterator getIterator(ZZCursor c, String dim) { + return new Iterator(new ZZCursorVirtual(c), dim); + } + +} + + + + + + diff --git a/Java/media/StringScroll.java b/Java/media/StringScroll.java new file mode 100644 index 0000000..100713b --- /dev/null +++ b/Java/media/StringScroll.java @@ -0,0 +1,310 @@ +/* +StringScroll.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, + * multiformat and UTF-8 format support by Antti-Juhani Kaijanaho + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A scroll of chars. May later have holes etc. from expunging, + * but basically the point is that the address to content mapping + * is stable and will not change whatever is done. + * + * The new StringScroll format is based on UTF-8. After the initial + * signature described shortly, the scroll writable is a plain UTF-8 + * sequence. The whole StringScroll should be + * + * The signature of the new StringSroll format is the octet sequence + * given in the "signature" attribute. + */ +public class StringScroll extends Scroll{ +public static final String rcsid = "$Id: StringScroll.java,v 1.8 2001/02/09 08:30:54 ajk Exp $"; + + /** Number of characters in a new-format "record". Records are + * implicit in the actual file; they are explicit only in the + * in-memory index. */ + static int recordsize = 1000; + + private Writable f; + private boolean readonly; + + private interface SSImpl { + char[] get(long start, int n); + long curEnd(); + long append(char[] bytes); + } + + private SSImpl ss; + + private byte[] signature = new byte[]{ (byte) 0xef, (byte) 0xbb, (byte) 0xbf, + (byte) 0x20, (byte) 0x20, (byte) 0x5a, + (byte) 0x5a, (byte) 0x53, (byte) 0x53, + (byte) 0x2d, (byte) 0x30, (byte) 0x0a }; + + private synchronized void determineFormat() { + boolean newformat; + if (f.length() == 0) { + if (readonly) { + newformat = false; + } else { + f.write(0, signature); + newformat = true; + } + } else if (f.length() < signature.length) { + newformat = false; + } else { + byte[] sig = f.read(0, signature.length); + // assume it's new format; check signature and note it's + // old format if signature does not match + newformat = true; + for (int i = 0; i < sig.length; i++) { + if (sig[i] != signature[i]) { + newformat = false; + break; + } + } + } + if (newformat) ss = new UTF8Format(); else ss = new OldFormat(); + } + + public StringScroll(String id, Writable w, boolean ro) { + super(id); + this.readonly = ro; + f = w; + determineFormat(); + } + + /** Get an array of characters of length n starting from the + * startth (or so) character. */ + public synchronized char[] get(long start, int n) { + return ss.get(start, n); + } + + // XXX ENCODING - currently 2 bytes / char :( + public String getString(long start, int n) { + char[] b = get(start,n); + String s = new String(b); + // p("GETS: "+start+" "+n+" "+b+" '"+s+"'"); + return s; + } + + public long curEnd() { + return ss.curEnd(); + } + + public synchronized long append(String b) { + p("Append - length: "+b.length()); + return append(b.toCharArray()); + } + + public synchronized long append(char[] bytes) { + return ss.append(bytes); + } + + private class UTF8Format implements SSImpl { + /** A private copy of recordsize in order to avoid changing + the parent recordsize from messing up the index. */ + private int recordsize; + + /** We store in the index the offset - counting from the + writable's start - of each recordsize character so that + index[n] contains the offset of the character at the + address n*recordsize. */ + private Vector index; + + /** Cache the address to be given to the next appended character. */ + private long nextAddr; + + /** Put an offset for an address (which must be a multiple of + * recordsize) into the index. */ + private void putOffs(long addr, long offs) { + if (addr % recordsize != 0) { + throw new ZZError("Address is not a record boundary"); + } + + // FIXME: Vector can index only using int's. This is bad. + long idx = addr / recordsize; + if (idx > Integer.MAX_VALUE) { + throw new ZZError("Internal error: idx too big"); + } + + if (idx >= index.size()) index.setSize((int) idx + 1); + + index.setElementAt(new Long(offs), (int)idx); + + // sanity check + if (lookupOffs(addr) != offs) { + throw new ZZError("Internal error: index add failure"); + } + } + + /** Look offset up by address (must be a multiple of + * recordsize). */ + private long lookupOffs(long addr) { + if (addr % recordsize != 0) { + throw new ZZError("Address is not in index"); + } + + // FIXME: Vector can index only using int's. This is bad. + long idx = addr / recordsize; + if (idx > Integer.MAX_VALUE) { + throw new ZZError("Internal error: idx too big"); + } + + return ((Long) index.elementAt((int) idx)).longValue(); + } + + public UTF8Format() { + index = new Vector(); + recordsize = StringScroll.this.recordsize; + + // Build the index by scanning the whole scroll + long offs = signature.length; + long addr = 0; + while (offs < f.length()) { + UTF8Char uc = new UTF8Char(f, offs); + + if (addr % recordsize == 0) { + putOffs(addr, offs); + } + + ++addr; + offs += uc.b.length; + } + nextAddr = addr; + } + + // Implementation of SSImpl + + public char[] get(long start, int n) { + char[] rv = new char[n]; + + int acc = 0; + // The loop body will read at most n characters starting + // from address start+acc by slurping the whole record and + // scanning there. The body is run repeatedly until we + // have exactly n characters in rv. + while (acc < n) { + // Step 1: Read the current record completely into memory + long recstart = (start + acc) - (start + acc) % recordsize; + long recoffs = lookupOffs(recstart); + byte[] record = f.read(recoffs, recordsize); + // Step 2: Scan the record for the start address + long sad = recstart; + long sof = 0; + while (sof < record.length) { + if (sad == start + acc) break; + UTF8Char uc = new UTF8Char(record, (int) sof); + sof += uc.b.length; + sad++; + } + // Step 3: Convert at most n bytes and at most to the + // end of the record from record[sad] into rv, using acc as + // the rv index. + for (int i = (int) sof; i < record.length;) { + if (acc == n) break; + UTF8Char uc = new UTF8Char(record, i); + rv[acc++] = uc.c; + i += uc.b.length; + } + } + + return rv; + } + + public long curEnd() { + return nextAddr; + } + + public long append(char[] chs) { + // We want to avoid doing unnecessary writes. Therefore, + // we first build an array of UTF-8 characters. Then we + // flatten it into an onedimensional array containing the + // UTF-8 representations in a row and write that. + UTF8Char[] ucs = new UTF8Char[chs.length]; + + long rv = nextAddr; + + int len = 0; + for (int i = 0; i < chs.length; i++) { + ucs[i] = new UTF8Char(chs[i]); + len += ucs[i].b.length; + } + + byte[] block = new byte[len]; + int bi = 0; + for (int i = 0; i < ucs.length; i++) { + // Update index + if ((nextAddr + i) % recordsize == 0) { + putOffs(nextAddr + i, f.length() + bi); + } + // Copy UTF-8 octets to block. + for (int j = 0; j < ucs[i].b.length; j++) { + block[bi++] = ucs[i].b[j]; + } + } + f.write(f.length(), block); + nextAddr += ucs.length; + + if (nextAddr - nextAddr % recordsize + != (index.size() - 1) * recordsize) { + throw new ZZError("Internal error: index not consistent"); + } + return rv; + } + + } + + private class OldFormat implements SSImpl { + public synchronized char[] get(long start, int n) { + byte[] b = f.read(start*2, n*2); + char[] c = new char[n]; + for(int i=0; i> 8) & 0xff); + byt[i*2+1] = (byte)((bytes[i] >> 0) & 0xff); + } + + // XXX race? + long c = f.length(); + if(c%1 != 0) throw new Error("Argh! Odd number of bytes"); + f.write(c, byt); + + return c / 2; + } + } +} + + + diff --git a/Java/media/TestLines.java b/Java/media/TestLines.java new file mode 100644 index 0000000..62e359b --- /dev/null +++ b/Java/media/TestLines.java @@ -0,0 +1,189 @@ +/* +TestLines.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; +import java.awt.*; + +/** Some tests for line breaking. + */ + +public class TestLines { +public static final String rcsid = "$Id: TestLines.java,v 1.10 2001/02/23 15:01:10 tjl Exp $"; + static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + Frame f = new Frame(); + +/* Jikes won't eat this any more in new versions due to äö. + static final String str = "Pikku stringi testataksemme rivinpilkkomista. "+ +"Tällä kertaa kirjoitammekin sen suomeksi - englanninkielisiä lukijoitamme "+ +"varmaankin hämmästyttää. Etenkin ääkköset. Tämä merkkijono piirretään "+ +"näytölle monta kertaa erilaisena, siis \"kursori\" eri kohdalle laitettuna. "+ +"Tästä voidaan sitten nähdä, toimiiko rivien pilkkominen palasiksi oikein. " + +"Itse asiassa merkkijonoa tulee vielä jonkin verran pidentää koska muuten " + +"emme ehdi nähdä kaikkia efektejä. Hauskaahan tästä tulee vasta sitten " + +"kun voimme oikeasti muokata näin näytettyä tekstiä mutta tämä testi on " + +"tärkeä askel siihen suuntaan mentäessä." +; + +*/ + + static final String str = "lsjifs lefjis elfj sef jsle fjslf "; + + class MyLayout implements SimpleLineInfo.Layout { + int c; + MyLayout(int c) { this.c = c; } + public FontMetrics getFontMetrics(int line) { + return fm[find(c, line)]; + } + public int getWidth(int line) { + return width(c, line); + } + public int getCenterLine() { return 0; } + + } + + public static void main(String[] argv) { + TestLines t = new TestLines(); + t.br(); + } + + int NTESTS = 1; + + int[][] lines = new int[NTESTS][]; + Font[] fonts = new Font[64]; + FontMetrics[] fm = new FontMetrics[fonts.length]; + { for(int i=0; i 400) w = 400; + return w; + } else if(cas == 1) { + int w =300 - 20 * line; + if(w < 50) return 50; + return w; + } else if(cas == 2) { + return (int)(100 + 200.0 / (1 + (line * line)/40.0)); + } + return -1; + } + + int curs = 0; + int dir = 1; + +public TestLines() { +} + +public void br() { + + + Component cp; + f.add( + cp= new Component() { + Image cache; + public void paint(Graphics g0) { + Thread.dumpStack(); + if(lines == null) return; + if(cache==null) { + cache = createImage(800,800); + } + Graphics g = cache.getGraphics(); + g.setColor(getBackground()); + g.fillRect(0, 0, 800, 800); + for(int set = 0; set < lines.length; set++) { + if(lines[set] == null) return; + int cur = 0; + int x = 20 + 400 * set; + int y = 100; + int line = lines[set][0]; + for(int i=0; i= cur && curs < lines[set][i+1]) { + // Trim is wrong :( + int cw = metr.stringWidth(str.substring(cur, curs).trim()); + g.setColor(Color.blue); + g.drawLine(x+cw, y-metr.getAscent(), + x+cw, y+metr.getDescent()); + } + + g.setColor(Color.red); + g.drawLine(x+width(cas, line), y-metr.getAscent(), + x+width(cas,line), y+metr.getDescent()); + cur = lines[set][i+1]; + y += metr.getDescent(); + line ++; + } + } + g0.drawImage(cache, 0, 0, null); + } + }); + f.setSize(800,800); + + SimpleLineBreaker slb = new SimpleLineBreaker(); + f.show(); + + while(true) { + for(int i=0; i= str.length()-5) dir = -dir; + } + } +} +} diff --git a/Java/media/UTF8Char.java b/Java/media/UTF8Char.java new file mode 100644 index 0000000..cf23a7b --- /dev/null +++ b/Java/media/UTF8Char.java @@ -0,0 +1,245 @@ +/* +UTF8Char.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag; + +import java.io.*; + +public class UTF8Char { +public static final String rcsid = "$Id: UTF8Char.java,v 1.3 2001/03/21 10:01:21 ajk Exp $"; + + public char c; + public byte[] b; + + /* UTF-8 <-> Java char conversion is table-driven. This code is + * adapted from CatDVI. */ + + private static class ConvOctet { + /** The number of variable bits, 1-8 */ + public int numbits; + /** The template for this octet */ + public byte octet; + + public ConvOctet(int n, byte o) { + numbits = n; + octet = o; + } + + public ConvOctet(int n, int o) { + this(n, (byte) o); + } + } + + private static class ConvEntry { + /** Maximum UCS-4 value encodable using this entry. */ + public char maxval; + /** Info on each octet. */ + ConvOctet[] template; + + public ConvEntry(char maxval, ConvOctet[] template) { + this.maxval = maxval; + this.template = template; + } + + public ConvEntry(int maxval, ConvOctet[] template) { + this((char) maxval, template); + } + + public final int len() { return template.length; } + } + + private static final ConvEntry[] convtbl = + new ConvEntry[] { + new ConvEntry (0x7f, + new ConvOctet[] { + new ConvOctet(7, 0) + }), + new ConvEntry (0x7ff, + new ConvOctet[] { + new ConvOctet(5, 0xc0), + new ConvOctet(6, 0x80) + }), + new ConvEntry (0xffff, + new ConvOctet[] { + new ConvOctet(4, 0xe0), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80) + }), + new ConvEntry (0x1fffff, + new ConvOctet[] { + new ConvOctet(3, 0xf0), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80) + }), + new ConvEntry (0x3ffffff, + new ConvOctet[] { + new ConvOctet(2, 0xf4), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80) + }), + new ConvEntry (0x7fffffff, + new ConvOctet[] { + new ConvOctet(1, 0xfc), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + new ConvOctet(6, 0x80), + }) + }; + + /** Convert a Java char into an UTF-8 octet stream. */ + public static byte[] charToUTF8(char c) { + // Stage 1: Determine which ConvEntry to use. We use the + // maxval attribute for this: the ConvEntry with smallest + // maxval where the char fits is used. + ConvEntry e = null; + for (int i = 0; i < convtbl.length; i++) { + if (c <= convtbl[i].maxval) { + e = convtbl[i]; + break; + } + } + if (e == null) throw new ZZError("character has no UTF-8 representation"); + + // Stage 2: Do the conversion from right to left. + byte[] rv = new byte[e.len()]; + for (int i = rv.length - 1; i >= 0; --i) { + /* At each iteration we first apply the initial bit + pattern and then patch the rest with the indicated + number of lower-order bits in code. When we are done, + we shift these out. */ + int numbits = e.template[i].numbits; + rv[i] = e.template[i].octet; + rv[i] |= ((1 << numbits) - 1) & c; + c = (char) (c >> numbits); + } + return rv; + } + + private static class UTF8ToCharRV { + public char c; + public int len; + public UTF8ToCharRV(char c, int len) { + this.c = c; + this.len = len; + } + } + + public static class InvalidChar extends ZZError { + public InvalidChar(String s) { super(s); } + } + + /** Determine the ConvEntry to be used. We determine this + using the first octet's template. */ + private static ConvEntry UTF8ConvEntry(byte o) { + for (int i = 0; i < convtbl.length; i++) { + byte b = (byte) (o & ~((1 << convtbl[i].template[0].numbits) - 1)); + if (convtbl[i].template[0].octet == b) { + return convtbl[i]; + } + } + return null; + } + /** Find out the length of an UTF-8 sequence based on the first + * octet. */ + public static int UTF8Len(byte o) { + ConvEntry e = UTF8ConvEntry(o); + if (e == null) throw new InvalidChar("this is no UTF-8 character"); + return e.len(); + } + + private static UTF8ToCharRV UTF8ToChar(byte[] array, int start) { + ConvEntry e = UTF8ConvEntry(array[start]); + if (e == null) return null; + + // Decode the octet stram. + char rv = 0; + for (int i = 0; i < e.template.length; i++) { + byte mask = (byte) ((1 << e.template[i].numbits) - 1); + byte fixed = (byte) (array[start + i] & ~mask); + byte bits = (byte) (array[start + i] & mask); + if (fixed != e.template[i].octet) throw new ZZError("Invalid UTF-8 character"); + rv = (char) ((rv << e.template[i].numbits) | bits); + } + return new UTF8ToCharRV(rv, e.template.length); + } + + private static void init(UTF8Char c, UTF8ToCharRV r, byte[] a, int start) { + if (r == null) throw new InvalidChar("Invalid UTF-8 character"); + c.c = r.c; + c.b = new byte[r.len]; + for (int i = 0; i < c.b.length; i++) { + byte b = a[start + i]; + c.b[i] = b; + } + } + + private UTF8Char(UTF8ToCharRV r, byte[] a, int start) { + init(this, r, a, start); + } + + public UTF8Char tryFromUTF8(byte[] a, int start) { + UTF8ToCharRV r = UTF8ToChar(a, start); + if (r == null) return null; + return new UTF8Char(r, a, start); + } + + /** Create an UTF-8 char from the byte stream (bytes after the + * character are ignored). You can determine how many bytes was + * used by invoking UTF8Len on the created object. */ + public UTF8Char(byte[] a) { this(a, 0); } + public UTF8Char(byte[] a, int start) { + init(this, UTF8ToChar(a, start), a, start); + } + + public UTF8Char(char c) { + this.c = c; + b = charToUTF8(c); + } + + public UTF8Char(Writable w, long offs) { + long len = (w.length() - offs < 6) ? w.length() - offs : 6; + byte[] a = w.read(offs, (int)len); + init(this, UTF8ToChar(a, 0), a, 0); + } + + static public void main(String argv[]) { + FileWritable fw; + try { + RandomAccessFile raf = new RandomAccessFile("test.utf8", "rw"); + fw = new FileWritable(raf); + } catch (IOException e) { + throw new ZZError("" + e); + } + + long offs = 0; + while (offs < fw.length()) { + UTF8Char uc = new UTF8Char(fw, offs); + System.out.println("H: " + (long) uc.c); + offs += uc.b.length; + } + + } +} + diff --git a/Java/media/VStream.java b/Java/media/VStream.java new file mode 100644 index 0000000..5e913e8 --- /dev/null +++ b/Java/media/VStream.java @@ -0,0 +1,655 @@ +/* +VStream.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** Utility functions for vstreams. + * NOTE! USE THE VirtualCursor OBJECTS ONLY SHORT-TERM, put stuff + * in the structure + * for longer term. + * ANY call to VStream.* routines invalidates all VirtualCursor objects pointing + * to that vstream. + *

    + * TODO: d.markup, active references to parts of another vstream + * (via including complete vstream objects!) + *

    + * The vstream format is simple: the headcell on d.2 is a dummy cell + * that is never moved (so that it remains easy to refer to the vstream). + * Note that cells with the span length of 0 (i.e. end less than start) + * are explicitly ALLOWED. + *

    + * Important policy decision pending: what to do about non-span cells + * in vstreams? + *

    + * In addition to pointers, we'll probably need spans (of vstream) to complement + * them, for formatting etc. + * @deprecated This is a bit old now - see e.g. Nile and Stream.java. + */ + +public class VStream { +public static final String rcsid = "$Id: VStream.java,v 1.28 2000/11/24 16:24:21 tjl Exp $"; + + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + static String dim = "d.2"; + static public class Rend { + public Span[] spans; + public String[] strs; + public ZZCell[] cells; + public int[][] marks; + public ZZCell[][] markcells; + } + + static public final void assertOffs(ZZCursor c) { + if(c.getOffs() == c.NO_OFFSET) + throw new ZZError("Need cursor offset"); + } + + static public ZZCursorVirtual add(ZZCursor vc, int o) { + assertOffs(vc); + + ZZCell c = vc.get(); + o += vc.getOffs(); + + // XXX Do we need to enforce spans? + while(o < 0) { + c = c.s(dim, -1); + if(c == null || c.getSpan() == null) return null; + o += (int)c.getSpan().length(); + } + while(o > c.getSpan().length()) { + o -= (int)c.getSpan().length(); + c = c.s(dim, 1); + if(c == null || c.getSpan() == null) return null; + } + return new ZZCursorVirtual(c, o); + } + + static public String error(ZZCell c) { + ZZCell s = c.h(dim, -1); + if(s.getSpan() != null) return "First cell has span"; + while((s=s.s(dim, 1))!=null) { + if(s.getSpan() == null) + return "No span in cell!"; + } + return null; + } + static public void check(ZZCell c) { + if(!dbg) return; + String e = error(c); + System.out.println("VSTREAM DUMP"); + for(ZZCell s = c.h(dim, -1); s != null; + s = s.s(dim, 1)) { + System.out.println("'"+s.getText()+"' from span: "+s.getSpan()); + } + if(e == null) return; + throw new ZZError("VStream error in stream! '"+e+"' dumped"); + } + + // The first cell is the second of the rank. + static public ZZCursor start(ZZCell c) { + c = c.h(dim, -1).s(dim, 1); + if(c==null) return null; + return new ZZCursorVirtual(c, 0); + } + static public ZZCursor end(ZZCell c) { + c = c.h(dim, 1); + return new ZZCursorVirtual(c, c.getText().length()); + } + + static public void create(ZZCell c, String dim, int dir, Span s) { + ZZCell n = c.N(dim, dir).N("d.2", 1); + if(s != null) + n.setSpan(s); + } + /** Find the first instance of the given character + * that occurs at position p or after. + */ + static public ZZCursor findChar(char c, ZZCursor p) { + assertOffs(p); + + String s = p.get().getText(); + int io = s.indexOf(c, p.getOffs()); + if(io != -1) return new ZZCursorVirtual(p.get(), io); + ZZCell cur = p.get(); + while((cur = cur.s(dim, 1))!=null) { + io = cur.getText().indexOf(c); + if(io != -1) return new ZZCursorVirtual(cur, io); + } + return null; + } + /** Return the string between two positions, inclusive. + */ + static public String getStr(ZZCursor p1, ZZCursor p2) { + p("getStr: "+p1+" "+p2); + assertOffs(p1); assertOffs(p2); + + StringBuffer s = new StringBuffer(); + if(p1.get() == p2.get()) { + return p1.get().getText().substring(p1.getOffs(), p2.getOffs()+1); + } + s.append(p1.get().getText().substring(p1.getOffs())); + ZZCell c = p1.get(); + while((c=c.s(dim,1)) != null && c != p2.get()) { + s.append(c.getText()); + } + if(c!=null) { + String str = c.getText(); + // Have to check whether one past end or end + if(str.length() > p2.getOffs()) + s.append(str.substring(0, p2.getOffs()+1)); + else + s.append(str); + } + return s.toString(); + } + // XXX Join the next two methods + static public Span[] getSpans(ZZCursor p1, ZZCursor p2) { + Vector sp = new Vector(); + p("getspans: "+p1+" "+p2+" "+p1.get()+" "+p2.get()); + p("getspans1: "+p1.get().getText()); + p("getspans2: "+p1.get().getSpan()); + p("getspans3: "+p1.get().getSpan().subSpan(p1.getOffs())); + if(p1.get() == p2.get()) { + sp.addElement( + p1.get().getSpan().subSpan(p1.getOffs(), p2.getOffs()+1) + ); + } else { + sp.addElement( + p1.get().getSpan().subSpan(p1.getOffs()) + ); + ZZCell c = p1.get(); + while((c=c.s(dim,1)) != null && c != p2.get()) { + sp.addElement(c.getSpan()); + } + if(c!=null) + sp.addElement(c.getSpan().subSpan(0, p2.getOffs()+1)); + } + Span[] ret = new Span[sp.size()]; + for(int i=0; i= o1) && (o2<0 || i <= o2)) { + if(res==null) res = new Vector(); + res.addElement(new Integer(i-o1)); + res.addElement(c); + } + } catch(NumberFormatException e) { + // Nothin' + } + } + if(res!=null) { + int[] r = new int[res.size()/2]; + ZZCell[] rc = new ZZCell[res.size()]; + for(int i=0 ;i= offs0) && + (offs1 < -1 || of <= offs1)) { + rnk[i].setText(""+(of-offs0+noffs)); + r.insert("d.cursor", 1, rnk[i]); + } + } catch(NumberFormatException e) { + // Nothin' + } + } + + } + + /** Split a VStream at position, return the cell just BEFORE the + * split. XXX MAYBE ALL VSTREAMS SHOULD HAVE EMPTY CELL AT BEGINNING AND + * END. + */ + static private ZZCell splitAt(ZZCursor p) { + // If offs == 0, need to do nothing. + if(p.getOffs() == 0) return p.get().s(dim, -1); + + Span cur = p.get().getSpan(); + if(p.getOffs() == cur.length()) return p.get(); + // In the middle -> split and reposition cursors. + ZZCell n1 = p.get().N(dim, 1); + n1.setSpan(cur.subSpan(p.getOffs())); + p.get().setSpan(cur.subSpan(0, p.getOffs())); + + ZZCell[] rnk = p.get().readRank("d.cursor", 1, false); + for(int i=0; i= p.getOffs()) { + int nof = of-p.getOffs(); + rnk[i].setText(""+nof); + n1.insert("d.cursor", 1, rnk[i]); + } + } catch(NumberFormatException e) { + // Nothin' + } + } + return p.get(); + } + + /** Insert a cut mark at the given position. + */ + static public void cut(ZZCursor p) { + ZZCell prev = splitAt(p); + ZZCell n = prev.s(dim, 1); + n.disconnect("d.cut", 1); + + n.connect("d.cut", 1, n); + } + /** Clear the cuts in the given vstream. + */ + static public void clearcuts(ZZCursor p) { + if ( p == null ) return ; + for(ZZCell c = p.get().h(dim, -1); c!=null; + c = c.s(dim, 1)) + if(c.s("d.cut", 1) != null) + c.disconnect("d.cut", 1); + } + + static ZZCell findPrevCut(ZZCursor p) { + ZZCell prev; + for(prev=p.get(); prev != null && prev.s("d.cut", 1) == null; + prev = prev.s(dim, -1)); + return prev; + } + static ZZCell findNextCut(ZZCursor p) { + ZZCell next; + for(next=p.get().s(dim, 1); next != null && + next.s("d.cut", 1) == null; + next = next.s(dim, 1)); + return next; + } + + /** Create a new vstream between the given cut marks. + * XXX This is difficult since Pos doesn't have the forwards-backwards + * info - Swing positions do. This should probably be added... + * Imagine cutting apart at single character edges... + */ + static public ZZCell separate(ZZCursor p) { + ZZCell prev = findPrevCut(p); + ZZCell next = findNextCut(p); + ZZCell tmp; + // based on their nullness, find the section to cut. + if(prev == null && next == null) return null; // nothing. + if(prev == null) { + next.disconnect("d.cut", 1); + next.disconnect(dim, -1); + tmp = p.get().h(dim, -1); + tmp.disconnect(dim, 1); + tmp.connect(dim, 1, next); + return p.get().h(dim, -1).N(dim, -1); + } else { + if(next != null){ + //prev.s(dim, -1).connect(dim, 1, next); + next.disconnect(dim, -1); + tmp = prev.s(dim, -1); + tmp.disconnect(dim, 1); + tmp.connect(dim, 1, next); + } + prev.disconnect(dim, -1); + prev.disconnect("d.cut", 1); + return prev.N(dim, -1); + } + // return null; + } + + /** Copy the part of the vstream between the nearest cut marks + * into a new vstream. + */ + static public ZZCell separateCopy(ZZCursor p) { + ZZCell nhead = p.get().N("d.tmp",1); + nhead.excise("d.tmp"); + ZZCell prev = findPrevCut(p); + ZZCell next = findNextCut(p); + if(prev == null) prev = p.get().h(dim, -1).s(dim, 1); + ZZCell n = nhead; + for(ZZCell c = prev; c != null && c != next; c=c.s(dim, 1)) { + n = n.N(dim, 1); + n.setSpan(c.getSpan()); + } + return nhead; + } + + + /** Insert the given span. + * Cursors at the insertion point will be moved to AFTER the + * insertion. XXX Here's something where more flexibility + * is needed: does a cursor point forwards or backwards? + */ + static public void insert(ZZCursor p, Span s) { + ZZCell prev = splitAt(p); + + Span cur = prev.getSpan(); + if(prev.getSpan() != null && prev.getSpan().isAppendable(s)) { + int len = (int)prev.getSpan().length(); + moveCurs(prev, len, len, prev, (int)(len+s.length())); + prev.setSpan(prev.getSpan().append(s)); + return; + } + ZZCell n = prev.N(dim, 1); + n.setSpan(s); + + moveCurs(p.get(), p.getOffs(), p.getOffs(), n, 1); + } + + /** Assimilate a whole vstream in insertion. + * Also places cuts at the beginning and the end of the result... + * XXX should it just return the POSes? + * XXX Delete the empty cells at ends... + */ + static public void assimilate(ZZCursor p, ZZCell vstream) { + ZZCell prev = splitAt(p); + ZZCell next = prev.s(dim, 1); + ZZCell firstof = vstream.h(dim, -1).s(dim, 1); + ZZCell tail = firstof.h(dim, 1); + prev.disconnect(dim, 1); + firstof.disconnect(dim, -1); + prev.connect(dim, 1, firstof); + firstof.connect("d.cut", 1, firstof); + if(next != null) { + next.disconnect("d.cut", 1); + next.connect("d.cut", 1, next); + next.connect(dim, -1, tail); + } + } + + /** A convenience function: delete one character prior to p0. + */ + static public void backspace(ZZCursor p0) { + // while and not if: there might be null-length + // spans in there... + while(p0.getOffs() == 0) { + ZZCell c = p0.get().s(dim, -1); + if(c == null || c.getSpan() == null || c.getSpan().length() == 0) + return; + p0 = new ZZCursorVirtual(c, (int)c.getSpan().length()); + } + // Split if needed + if(p0.getOffs() != p0.get().getSpan().length()) { + ZZCell prev = splitAt(p0); + p0.set(prev); + } + // Now we know p0.offs == p0.get().getSpan().length()... + int l = (int)(p0.get().getSpan().length()); + if(l==1) { + // move cursors and delete cell + // XXX AUGH! Must move EITHER forwards or backwards, + // depending on which one is there... + ZZCell to = p0.get().s(dim, 1); int offs = 0; + if(to==null) { + to = p0.get().s(dim, -1); + offs = (int)to.getSpan().length(); + } + // Ouch... + moveCurs(p0.get(), 0, 0, to, offs); + moveCurs(p0.get(), 1, 1, to, offs); + p0.get().delete(); + return; + } + p0.get().setSpan(p0.get().getSpan().subSpan(0, l-1)); + moveCurs(p0.get(), l, l, p0.get(), l-1); + } + + + // XXX Maybe too heavy - always creates new cells. + // untested. + static public void delete(ZZCursor p0, ZZCursor p1) { + ZZCell[] rnk; + if(p0.get() == p1.get()) { + ZZCell n = p0.get().N(dim, 1); + p0.get().setSpan(p0.get().getSpan().subSpan(0, p0.getOffs())); + n.setSpan(p0.get().getSpan().subSpan(p1.getOffs()+1)); + // Then, redo cursors + rnk = p0.get().readRank("d.cursor", 1, false); + for(int i=0; i p1.getOffs()) { + int nof = of-p1.getOffs()-1; + rnk[i].setText(""+nof); + n.insert("d.cursor", 1, rnk[i]); + } else if(of >= p0.getOffs()) { + rnk[i].setText(""+p0.getOffs()); + } + } catch(NumberFormatException e) { + // Nothin' + } + } + } else { + // 1. first cell's span & cursors + p0.get().setSpan(p0.get().getSpan().subSpan(0, p0.getOffs())); + rnk = p0.get().readRank("d.cursor", 1, false); + for(int i=0; i= p0.getOffs()) { + rnk[i].setText(""+p0.getOffs()); + } + } catch(NumberFormatException e) { + // Nothin' + } + } + // Do the cells until we get to the second cell. + ZZCell c = p0.get(); + while((c = c.s(dim, 1)) != null && c != p1.get()) { + rnk = c.readRank("d.cursor", 1, false); + for(int i=0; i p1.getOffs()) { + int nof = of-p1.getOffs()-1; + rnk[i].setText(""+nof); + } else { + p0.get().insert("d.cursor", 1, rnk[i]); + rnk[i].setText(""+p0.getOffs()); + } + } catch(NumberFormatException e) { + // Nothin' + } + } + + } + } + /** Given a blank cell, set that cell's span and add extra + * cells as necessary to copy the span between p0 and p1. + */ + static public void copyNew(ZZCursor p0, ZZCursor p1, ZZCell blank) { + if(p0.get()==p1.get()) { + blank.setSpan(p0.get().getSpan().subSpan(p0.getOffs(), p1.getOffs()+1)); + } else { + // First cell + blank.setSpan(p0.get().getSpan().subSpan(p0.getOffs())); + // middle cells + ZZCell c = p0.get(); + ZZCell n = blank; + while((c = c.s(dim, 1)) != null && c != p1.get()) { + n = n.N("dim", 1); + n.setSpan(c.getSpan()); + } + // Last cell + if(c==null) return; + n = n.N("dim", 1); + n.setSpan(p1.get().getSpan().subSpan(0, p1.getOffs()+1)); + } + } +} + + + diff --git a/Java/media/ZZDefaultText.java b/Java/media/ZZDefaultText.java new file mode 100644 index 0000000..8773d2f --- /dev/null +++ b/Java/media/ZZDefaultText.java @@ -0,0 +1,100 @@ +/* +ZZDefaultText.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; + +/** A simple implementation of ZZText. + */ + +public class ZZDefaultText extends ZZText { +String rcsid = "$Id: ZZDefaultText.java,v 1.2 2000/10/19 17:04:26 tjl Exp $"; + + public String getText(ZZCell c) { + return c.getText(); + } + + public void setText(ZZCell c, String s) { + c.disconnect("d.reftext", 1); + // XXX Delete all cells there too? + c.setText(s); + } + + public boolean isRef(ZZCell c) { + return c.s("d.reftext") != null; + } + + public void delete(ZZCell c, int start) { + // XXX faster + delete(c, start, getText(c).length()); + } + + public void delete(ZZCell c, int start, int end) { + if(isRef(c)) { + } else { + } + } + + public void insertNewRef(ZZCell c, String txt, int offs) { + ensureRef(c); + } + + public void insertRef(ZZCell c, Span sp, int offs) { + ensureRef(c); + } + + public Span[] getSpans(ZZCell c) { + LoopDetector ld = new LoopDetector(); + ZZCell v = c.s("d.reftext"); + return null; + } + public Span[] getSpans(ZZCell c, int start) { + LoopDetector ld = new LoopDetector(); + ZZCell v = c.s("d.reftext"); + return null; + } + public Span[] getSpans(ZZCell c, int start, int end) { + LoopDetector ld = new LoopDetector(); + ZZCell v = c.s("d.reftext"); + return null; + } + public void setSpans(ZZCell c, Span[] spans) { + } + + + Span makeSpan(ZZCell c, String s) { + StringScroll sc = c.getSpace().getStringScroll(); + long offs = sc.append(s); + return Span.create(Address.scrollOffs(sc, offs), + Address.scrollOffs(sc, offs+s.length()-1)); + } + + void ensureRef(ZZCell c) { + if(c.s("d.reftext") == null) { + Span sp = makeSpan(c, getText(c)); + ZZCell n = c.N("d.reftext", 1); + n.setSpan(sp); + } + } + +} + diff --git a/Java/media/ZZHumber.java b/Java/media/ZZHumber.java new file mode 100644 index 0000000..a29061c --- /dev/null +++ b/Java/media/ZZHumber.java @@ -0,0 +1,57 @@ +/* +ZZCellScroll.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; + +import java.io.*; + +/** A package for representing, reading and writing huge numbers. + * Humbers are described in Ted Nelson's Literary Machines. + * The ZZHumber objects are immutable, like the Java String class. + * XXX Not yet working + */ + +// Immutable +public class ZZHumber { +public static final String rcsid = "$Id: ZZHumber.java,v 1.3 2000/09/19 10:32:00 ajk Exp $"; + byte[] bytes; // The raw humber bytes. + public boolean equals(Object o) { + ZZHumber h = (ZZHumber) o; + if(h.bytes.length != bytes.length) return false; + for(int i=0; i + * Calling this function on a cell that only has text content + * makes the whole + * current text content referential as well. + */ + public abstract void insertNewRef(ZZCell c, String txt, int offs); + + /** Insert a referential span of text. + *

    + * Calling this function on a cell that only has text content + * makes the whole + * current text content referential as well. + */ + public abstract void insertRef(ZZCell c, Span sp, int offs); + + /** Obtain the referential contents of this cell. + * @return List of spans, or null if not referential. + */ + public abstract Span[] getSpans(ZZCell c); + public abstract Span[] getSpans(ZZCell c, int start); + public abstract Span[] getSpans(ZZCell c, int start, int end); + + /** Set the spans of the cell to the given spans. + */ + public abstract void setSpans(ZZCell c, Span[] spans); + + +} diff --git a/Java/mungencss.pl b/Java/mungencss.pl new file mode 100644 index 0000000..1bec803 --- /dev/null +++ b/Java/mungencss.pl @@ -0,0 +1,9 @@ +#!/usr/bin/perl -n + +# Don't include automatically generated subs +/\.readParams\b/ and next LINE; + +# Don't include Recs.java: both autogenerated and deprecated. +/\bRecs\b/ and next LINE; + +print; diff --git a/Java/net/Peer.java b/Java/net/Peer.java new file mode 100644 index 0000000..b37926d --- /dev/null +++ b/Java/net/Peer.java @@ -0,0 +1,61 @@ +/* +Peer.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* Written by Antti-Juhani Kaijanaho */ + +package org.gzigzag.net; + +import java.net.*; + +/** A networking peer: a pair (host, port). This is used by the + * reliable UDP scheme. */ +public final class Peer { + + private InetAddress host; + private int port; + + public Peer(InetAddress host, int port) { + this.host = host; + this.port = port; + } + + public InetAddress getHost() { + return host; + } + + public int getPort() { + return port; + } + + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof Peer)) return false; + + Peer p = (Peer)o; + + return host.equals(p.host) && port == p.port; + } + + public int hashCode() { + return host.hashCode() ^ port; + } + + public String toString() { + return host.toString() + ":" + port; + } + +} diff --git a/Java/net/ReliableUDPMessage.java b/Java/net/ReliableUDPMessage.java new file mode 100644 index 0000000..af39604 --- /dev/null +++ b/Java/net/ReliableUDPMessage.java @@ -0,0 +1,71 @@ +/* +ReliableUDPMessage.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* Written by Antti-Juhani Kaijanaho */ + +package org.gzigzag.net; +import java.text.*; +import java.util.*; + +/** An abstract superclass of all message classes for the Reliable UDP + * scheme. + * The message contains enough metainformation so that delivery + * can be guaranteed using an acknowledgment scheme. + *

    + * This superclass contains almost all functionality that + * ReliableUDPSocket needs from subclasses of this class; all + * subclasses need to do is implementing their own payload + * functionality. The only exception is that the subclass must take + * care of including the values from getSeq() and getAck() in the UDP + * payload. + */ +public abstract class ReliableUDPMessage { + private long seq = 0; + private long ack = 0; + private long timestamp = 0; + private Peer peer = null; + + static private DateFormat df = DateFormat.getDateInstance(); + + public final synchronized long getSeq() { return seq; } + public final synchronized long getAck() { return ack; } + public final synchronized long getTimestamp() { return timestamp; } + + public final synchronized void setSeq(long seq) { this.seq = seq; } + public final synchronized void setAck(long ack) { this.ack = ack; } + public final synchronized void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public final synchronized Peer getPeer() { return peer; } + public final synchronized void setPeer(Peer p) { peer = p; } + + /** Return a fresh byte array usable as UDP packet payload. Note + * that the return value must encode seq and ack to work with a + * ReliableUDPSocket; timestamp is optional. */ + public abstract byte[] toByteArray(); + + /** Make a fresh copy of this message. */ + public abstract ReliableUDPMessage copy(); + + public synchronized String toString() { + return "[" + df.format(new Date(timestamp)) + + "] " + peer; + } + +} + diff --git a/Java/net/ReliableUDPMessageFactory.java b/Java/net/ReliableUDPMessageFactory.java new file mode 100644 index 0000000..0ac73f3 --- /dev/null +++ b/Java/net/ReliableUDPMessageFactory.java @@ -0,0 +1,40 @@ +/* +ReliableUDPMessageFactory.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* Written by Antti-Juhani Kaijanaho */ + +package org.gzigzag.net; + +/** A factory creating ReliableUDPMessage objects for the use of a + * ReliableUDPSocket. + * Typically each application of the reliable UDP + * scheme implements this interface along with subclassing + * ReliableUDPMessage. + */ +public interface ReliableUDPMessageFactory { + + /** Create a ReliableUDPMessage object from the bytes given. Note + * that the seq, ack and optionally timestamp fields in the + * ReliableUDPMessage need to be set from the message too. */ + ReliableUDPMessage makeMessage(byte[] message); + + /** Create a fresh ReliableUDPMessage that is a no-op to a + * receiver. The return value is used to a acknowledge packets + * when no payload is available for the ack message. */ + ReliableUDPMessage makeNoOp(); + +} diff --git a/Java/net/ReliableUDPSocket.java b/Java/net/ReliableUDPSocket.java new file mode 100644 index 0000000..b3f14a7 --- /dev/null +++ b/Java/net/ReliableUDPSocket.java @@ -0,0 +1,321 @@ +/* +ReliableUDPSocket.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* Written by Antti-Juhani Kaijanaho */ + +package org.gzigzag.net; + +import org.gzigzag.*; +import java.io.*; +import java.net.*; +import java.util.*; + + +/** A socket for sending and receiving reliable UDP messages. + * This + * reliable UDP scheme guarantees delivery of a message but does not + * guarantee order of delivery. + * It does not specify a format for the + * UDP payload. + * Users of this class must implement + * ReliableUDPMessageFactory and pass that implementation to the + * constructor. + */ +public class ReliableUDPSocket implements SafeExit.Cleanupable { +public static final String rcsid = "$Id: ReliableUDPSocket.java,v 1.3 2001/03/18 20:22:11 tjl Exp $"; + public static boolean dbg = false; + protected static void p(String s) { if(dbg) ZZLogger.log(s); } + protected static void pa(String s) { ZZLogger.log(s); } + + /** Construct a reliable UDP socket and bind it to some local + * port. */ + public ReliableUDPSocket(ReliableUDPMessageFactory fact) throws SocketException { + this(fact, new DatagramSocket()); + } + + /** Construct a reliable UDP socket and bind it to the given local + * port. */ + public ReliableUDPSocket(ReliableUDPMessageFactory fact, int port) throws SocketException { + this(fact, new DatagramSocket(port)); + } + + private ReliableUDPSocket(ReliableUDPMessageFactory fact, DatagramSocket socket) { + this.fact = fact; + this.socket = socket; + this.local = new Peer(socket.getLocalAddress(), socket.getLocalPort()); + qflusher.start(); + } + + /** Send the given message. */ + public void send(ReliableUDPMessage rum) { + p("==> " + rum); + ReliableUDPMessage m = rum.copy(); + m.setTimestamp(System.currentTimeMillis()); + PeerEntry pe = getPeer(m); + pe.setseq(m); + pe.enqueue(m); + } + + /** Receive a message. */ + public ReliableUDPMessage receive() throws IOException { + synchronized (buf) { + DatagramPacket packet = new DatagramPacket(buf, buf.length); + ReliableUDPMessage m; + PeerEntry pe; + do { + socket.receive(packet); + byte[] bytes = new byte[packet.getLength()]; + byte[] origbytes = packet.getData(); + for (int i = 0; i < bytes.length; i++) bytes[i] = origbytes[i]; + m = fact.makeMessage(bytes); + m.setPeer(new Peer(packet.getAddress(), packet.getPort())); + pe = getPeer(m); + pe.acknowledge(m); + pe.process_ack(m); + } while (pe.duplicate(m)); + p("<== " + m); + return m; + } + } + + /** Get the local address and port. */ + public Peer getLocal() { + return local; + } + + /** Get an array of currently active peers. */ + public Peer[] getActivePeers() { + synchronized (peers) { + Peer[] rv = new Peer[peers.size()]; + int i = 0; + for (Enumeration e = peers.elements(); e.hasMoreElements();) { + rv[i++] = (Peer)e.nextElement(); + } + return rv; + } + } + + /** Return a rough measure of the roundtrip time between us and + * the indicated peer, given in milliseconds. If the peer is not + * active, the return value is Long.MAX_VALUE. Note that this + * will not cause packets to be sent. */ + public long getPeerLag(Peer p) { + synchronized (peers) { + if (!peers.containsKey(p)) return Long.MAX_VALUE; + PeerEntry pe = getPeer(p); + return pe.getMeasAverage(); + } + } + + public void close() { + try { + socket.close(); + qflusher.interrupt(); + qflusher.join(); + qflusher = null; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + public void cleanup() { + close(); + } + + // PRIVATE STUFF + + private final ReliableUDPMessageFactory fact; + private final DatagramSocket socket; + private final Peer local; + private final Hashtable peers = new Hashtable(); + private final byte[] buf = new byte[65536]; + private QueueFlusher qflusher = new QueueFlusher(); + + private final class PeerEntry { + private final class Outgoing { + public ReliableUDPMessage m; + public long time_entered = 0; + public long last_sent = 0; + } + + private Vector outgoing = new Vector(); + private Vector received = new Vector(); + private boolean needAck = false; + private long ack = 0; + private long seq = 1; + private Peer peer; + private long lastSend = 0; + + // for lag measurement + private long[] meas = new long[16]; // any number, really + private int measi = 0; + private int num_meas = 0; + + public PeerEntry(Peer peer) { this.peer = peer; } + + private synchronized void addReceived(Long l) { + received.addElement(l); + int n = received.size(); + int i; + for (i = n - 1; i >= 1; i++) { + Long a = (Long)received.elementAt(i - 1); + Long b = (Long)received.elementAt(i); + if (a.longValue() < b.longValue()) break; + received.setElementAt(a, i); + received.setElementAt(b, i - 1); + } + if (n >= 2 && received.elementAt(i).equals(received.elementAt(i+1))) { + received.removeElementAt(i+1); + } + } + + public synchronized boolean duplicate(ReliableUDPMessage rum) { + if (rum.getSeq() <= seq) return true; + if (received.contains(new Long(rum.getSeq()))) return true; + return false; + } + + private synchronized void addMeasurement(long m) { + meas[measi] = m; + measi = (measi + 1) % meas.length; + if (num_meas < meas.length) ++num_meas; + } + + public synchronized long getMeasAverage() { + if (num_meas == 0) return Long.MAX_VALUE; + long sum = 0; + for (int i = 0; i < num_meas; i++) { + sum += meas[i]; + } + return sum / num_meas; + } + + public synchronized void acknowledge(ReliableUDPMessage rum) { + needAck = true; + if (rum.getAck() > ack) addReceived(new Long(rum.getSeq())); + + int n = received.size(); + int i; + for (i = 0; i < n; i++) { + long l = ((Long)received.elementAt(i)).longValue(); + if (l != ack + i + 1) break; + } + Vector v = new Vector(); + ack += i; + for (int j = i; j < n; i++) { + v.addElement(received.elementAt(i)); + } + received = v; + } + + public synchronized void process_ack(ReliableUDPMessage rum) { + int n = outgoing.size(); + Vector v = new Vector(); + for (int i = 0; i < n; i++) { + Outgoing og = (Outgoing)outgoing.elementAt(i); + if (og.m.getSeq() > rum.getAck()) { + v.addElement(og); + } else if (og.m.getSeq() == rum.getAck()) { + addMeasurement(System.currentTimeMillis() - og.last_sent); + } + } + outgoing = v; + } + + public synchronized void enqueue(ReliableUDPMessage m) { + Outgoing og = new Outgoing(); + og.m = m; + og.time_entered = System.currentTimeMillis(); + og.last_sent = 0; + + outgoing.addElement(og); + trySend(og); + } + + public synchronized void setseq(ReliableUDPMessage rum) { + rum.setSeq(seq++); + } + + public synchronized void flush() { + int n = outgoing.size(); + for (int i = 0; i < n; i++) { + Outgoing og = (Outgoing)outgoing.elementAt(i); + trySend(og); + if (og.last_sent - og.time_entered > 10 * 60 * 1000) { + peers.remove(peer); + return; + } + } + if (needAck) { + Outgoing og = new Outgoing(); + og.m = fact.makeNoOp(); + og.m.setSeq(0); + trySend(og); + } + } + + private void trySend(Outgoing og) { + long now = System.currentTimeMillis(); + if (now - og.last_sent < 500) return; + og.m.setAck(ack); + needAck = false; + lastSend = now; + byte[] bytes = og.m.toByteArray(); + DatagramPacket dp = new DatagramPacket(bytes, bytes.length, + peer.getHost(), peer.getPort()); + try { + socket.send(dp); + } catch (IOException e) { + needAck = true; + } + og.last_sent = now; + } + + } + + private PeerEntry getPeer(ReliableUDPMessage rum) { + Peer p = rum.getPeer(); + return getPeer(p); + } + + private PeerEntry getPeer(Peer p) { + synchronized (peers) { + if (!peers.containsKey(p)) { + peers.put(p, new PeerEntry(p)); + } + return (PeerEntry)peers.get(p); + } + } + + private final class QueueFlusher extends Thread { + public void run() { + while (!isInterrupted()) { + try { + sleep(500); + Peer[] ps = getActivePeers(); + for (int i = 0; i < ps.length; i++) { + getPeer(ps[i]).flush(); + yield(); + } + } catch (InterruptedException e) { + interrupt(); + } + } + } + } + +} diff --git a/Java/p2p/P2PStorage.java b/Java/p2p/P2PStorage.java new file mode 100644 index 0000000..3e0d4fd --- /dev/null +++ b/Java/p2p/P2PStorage.java @@ -0,0 +1,82 @@ +/* +P2PStorage.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag.p2p; + +/** The physical layers of the mediaserver p2p layer. + * This is a mechanism layer; no policy is included here. + * For example, uncache unconditionally deletes the given span + * from the cache. Higher-up levels are expected to make e.g. reference + * counting functionality available to yet higher levels. + *

    + * This level simply associates unique ids to permanent, immutable + * blocks of bits: the important invariant is that + * get(id, offs, len) always returns either the same bits or + * an error if the bits are unobtainable at that time. + *

    + * Later on, digital signature functionality will be provided + * to help this. + */ + +interface P2PStorage { +public static final String rcsid = "$Id: P2PStorage.java,v 1.2 2001/04/02 17:23:44 tjl Exp $"; + + /** Convert a string to a unique id object. + */ + UniqueID str2id(String s); + + /** Get the length of the bits pointed to by the given id. + */ + long length(UniqueID id); + + /** Get the given bytes from the given id. + */ + byte[] get(UniqueID id, long offs, long len); + + /** Get an input stream from the given id. + */ + java.io.InputStream getInputStream(UniqueID id, long offs, long len); + + /** Store the given span in the cache. + */ + void cache(UniqueID id, long offs, long len); + + /** Remove the given span from the cache. + */ + void uncache(UniqueID id, long offs, long len); + + /** A structure showing a single cached entry. + */ + class InCache { + UniqueID id; + long offs, len; + } + /** Get a listing of the local cache/storage. + */ + InCache[] getDirectory(); + + /** Create a new globally unique id that can then be written to. + */ + UniqueID.Writable newUniqueID(); +} + diff --git a/Java/p2p/UniqueID.java b/Java/p2p/UniqueID.java new file mode 100644 index 0000000..4771e67 --- /dev/null +++ b/Java/p2p/UniqueID.java @@ -0,0 +1,54 @@ +/* +UniqueID.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag.p2p; + +/** A unique bit-block identifier. + * These identifiers are supposed to be globally unique and + * identify a single, continuous block of bits. + * @see Phys + */ + +interface UniqueID { +public static final String rcsid = "$Id: UniqueID.java,v 1.2 2001/04/02 17:23:44 tjl Exp $"; + + /** A simple representation of the whole ID as a string. + * Phys.str2id(s) is the inverse. + */ + String toString(); + + /** A writable version. + */ + interface Writable extends UniqueID { + /** Get a stream for writing into the object + * represented by this unique id. + * Naturally, this is only usable once; calling + * it more than once results in an exception. + * Closing the stream finalizes the object - + * it's not visible anywhere prior to that. + */ + java.io.OutputStream getOutputStream(); + } +} + + diff --git a/Java/part/BinaryTreePart.java b/Java/part/BinaryTreePart.java new file mode 100644 index 0000000..daf6e39 --- /dev/null +++ b/Java/part/BinaryTreePart.java @@ -0,0 +1,100 @@ +/* +BinaryTreePart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** EXPERIMENTAL: A full binary tree spacepart demo. + * Supports two local dimensions: depth and breadth. + */ + +public class BinaryTreePart extends ZZROStrSpacePart { +public static final String rcsid = "$Id: BinaryTreePart.java,v 1.3 2000/11/06 12:39:39 tjl Exp $"; + + public BinaryTreePart(ZZSpace space, String id) { + super(space, id); + } + + public String homeID() { + return "1"; + } + + public String getText(ZZCellHandle c) { + return c.id.substring(c.id.length()-1); + } + + public ZZDimension getDim(String name) { + if(name.equals("depth")) return new Depth(); + if(name.equals("breadth")) return new Breadth(); + return null; + } + + public class Depth extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + // We can go one step + if(c.part == null && c.id.equals("1") && steps > 0) { + c = this.space.getCellByID(BinaryTreePart.this, "1", null); + steps --; + } + + if(c.part != BinaryTreePart.this) return null; + + while(steps > 0 && c != null) { + c = (ZZCellHandle)this.space.getCellByID(c.id+"0"); + steps--; + } + while(steps < 0 && c != null) { + if(c.part != BinaryTreePart.this) return null; + int len = c.id.length(); + if(c.id.charAt(len-1) == '0') + c = (ZZCellHandle)this.space.getCellByID(c.id.substring(0, len-1)); + else if(c.id.equals(id+":"+1)) + c = (ZZCellHandle)this.space.getCellByID("1"); + else + c = null; + steps++; + } + return c; + } + } + + public class Breadth extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(c.part != BinaryTreePart.this) return null; + + if(steps == 0) return c; + if(steps == 1) { + int len = c.id.length(); + if(c.id.charAt(len-1) == '0') + return (ZZCellHandle)this.space.getCellByID(c.id.substring(0, len-1)+"1"); + } else if(steps == -1) { + int len = c.id.length(); + if(c.id.charAt(len-1) == '1' && + c.id.charAt(len-2) != ':') + return (ZZCellHandle)this.space.getCellByID(c.id.substring(0, len-1)+"0"); + } + return null; + } + } + +} + diff --git a/Java/part/DoubleStepPart.java b/Java/part/DoubleStepPart.java new file mode 100644 index 0000000..9df100f --- /dev/null +++ b/Java/part/DoubleStepPart.java @@ -0,0 +1,64 @@ +/* +DoubleStepPart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** EXPERIMENTAL: A dimension double-stepper part. + * This part, unlike most, has none of its own cells but simply + * provides for each dimension a doubling dimension. + */ + +public class DoubleStepPart extends ZZROStrSpacePart { +public static final String rcsid = "$Id: DoubleStepPart.java,v 1.1 2000/11/06 12:39:39 tjl Exp $"; + public static final boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + + public DoubleStepPart(ZZSpace space, String id) { + super(space, id); + } + + public String homeID() { + return "1"; + } + + public String getText(ZZCellHandle c) { + return c.id.substring(c.id.length()-1); + } + + public ZZDimension getDim(String name) { + return new Dbl(space.d(name)); + } + + public class Dbl extends ZZRODimension { + ZZDimension dim; + public Dbl(ZZDimension dim) { + this.dim = dim; + } + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + ZZCellHandle hd = dim.s(c, steps*2, o); + p("Dbl: Step "+steps+" "+c+" "+hd); + return hd; + } + } +} + diff --git a/Java/part/GenTreePart.java b/Java/part/GenTreePart.java new file mode 100644 index 0000000..0f49501 --- /dev/null +++ b/Java/part/GenTreePart.java @@ -0,0 +1,160 @@ +/* +GenTreePart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** EXPERIMENTAL: A tree implied by a sequence, done in a generic way. + * This is a tree implied by a structure, but in a generic way: an interface, + * GTreePartModel, is used to provide the tree structure. + *

    + * I still don't know whether Parsed helps... + * @see GenTreePart + */ + +public class GenTreePart extends ZZSpacePart { +public static final String rcsid = "$Id: GenTreePart.java,v 1.2 2000/11/16 21:01:56 tjl Exp $"; + + static public class Parsed { + String orig; + int depth; + } + + GenTreePartModel model; + + Depth dd = new Depth(); + Breadth db = new Breadth(); + + public GenTreePart(ZZSpace space, String id, GenTreePartModel model) { + super(space, id); + this.model = model; + } + + public ZZDimension getDim(String name) { + if(name.equals("depth")) return dd; + if(name.equals("breadth")) return db; + return null; + } + + public class Depth extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(steps == 0) return c; + + int level; + int maxlevel ; + + if(c.part == GenTreePart.this) { + Parsed par = (Parsed)c.parsedID; + level = par.depth; + c = (ZZCellHandle)this.space.getCellByID(par.orig); + maxlevel = model.depth(c); + } else { + // It's either beginning or also end of rank. + level = model.depth(c); + if(level == -1) return null; + maxlevel = level; + } + if(maxlevel < 0) return null; + level -= steps; + if(level < 0) return null; + if(level > maxlevel) return null; + if(level == maxlevel) return c; + return GenTreePart.this.space.getCellByID( + GenTreePart.this, + level + "-" + c.id); + + } + } + + public class Breadth extends ZZDimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(steps == 0) return c; + ZZCell searchFrom; + int level; + if(c.part == GenTreePart.this) { + Parsed par = (Parsed)c.parsedID; + level = par.depth; + c = (ZZCellHandle)this.space.getCellByID(par.orig); + } else { + level = model.depth(c); + if(level < 0) return null; + } + + ZZCell n = model.getNext(level, c, steps); + if(n == null) return null; + int lastlevel = model.depth(n); + + // Return our cell: the cell we ended up at may be at higher level. + if(lastlevel > level) { + return GenTreePart.this.space.getCellByID( + GenTreePart.this, + level + "-" + n.getID()); + } else { + return (ZZCellHandle)n; + } + } + + public void disconnect(ZZCellHandle c, int dir) { + // Only do it negwards + if(dir > 0) { + ZZCellHandle c2 = s(c, 1); + if(c2 != null) + disconnect(c2, -1); + return; + } + // Get headcell + ZZCell ct = dd.h(c, -1); + model.disconnectNeg(ct); + } + public void connect(ZZCellHandle c, ZZCellHandle d) { + if(s(c, 1) != null) + throw new ZZConnectWouldBreakError("In gentreedepth"); + if(s(d, -1) != null) + throw new ZZConnectWouldBreakError("In gentreedepth2"); + ZZCell c1 = dd.h(c, -1); + ZZCell d1 = dd.h(d, -1); + model.connect(c1, d1); + } + } + + + public String getText(ZZCellHandle c) { + return "+"; + } + public void setContent(ZZCellHandle c, Object o) { + } + + public Object parseIDPart(String idPart) { + int min = idPart.indexOf("-"); + Parsed ret = new Parsed(); + ret.orig = idPart.substring(min+1); + ret.depth = Integer.parseInt(idPart.substring(0, min)); + return ret; + } + + public String generateIDPart(Object parsed) { + Parsed p = (Parsed)parsed; + return p.depth+"-"+p.orig; + } + +} + diff --git a/Java/part/GenTreePartModel.java b/Java/part/GenTreePartModel.java new file mode 100644 index 0000000..a3b6c44 --- /dev/null +++ b/Java/part/GenTreePartModel.java @@ -0,0 +1,77 @@ +/* +GTreePartModel.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A tree model that provides enough information for GTreePart to + * make a tree appear in the structure. + * Assumes that a real (or at least not generated by this GTreePart) cell + * exists for each tree node or leaf. + * The depth in the tree is a constant, and depth is counted from leaves + * upwards, starting from 0, and the largest depth(cell) is depth()-1. + *

    + * This interface is heavily geared towards the thinking of having + * a single rank of cells, onto which the information about the levels + * of hierarchy is somehow connected. + * The same cell should not be given at different depths so + * using the marker cells is recommended. + *

    + * These are NOT documented clearly enough - see the sample implementation + * in ../Modules/nile or GTreePartTestModel. + * @see GenTreePart + */ + +public interface GenTreePartModel { +String rcsid = "$Id: GenTreePartModel.java,v 1.1 2000/11/16 00:25:10 tjl Exp $"; + /** The depth of the whole tree. + */ + int depth(); + + /** The depth of this cell. + * This method should return -1 if the cell does not belong + * to the tree properly. + */ + int depth(ZZCell c); + + /** Move N steps of at least this depth pos- or negwards. + */ + ZZCell getNext(int mindepth, ZZCell c, int steps); + + /** Disconnect negwards from the given cell. + */ + void disconnectNeg(ZZCell c); + + /** Connect the given cell poswards to the other. + */ + void connect(ZZCell c, ZZCell d); + + /** Set the depth of the given cell. + * This method should ONLY touch the depth of the given cell. + * Its virtual "children" will be handled by the GTreePart. + */ + void setDepth(ZZCell c, int d); +} + + + + diff --git a/Java/part/GenTreeTestModel.java b/Java/part/GenTreeTestModel.java new file mode 100644 index 0000000..73412c3 --- /dev/null +++ b/Java/part/GenTreeTestModel.java @@ -0,0 +1,83 @@ +/* +GTreePartTestModel.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A simple model to test GenTreePart. + * The same model as ImpliedTreePart has, except that the depth + * numbers are reversed and are 0, 1, 2 and 3. + * The actual cells in the stream are not included in the tree, only + * the section marker cells. + * @see GenTreePart + */ + +public class GenTreeTestModel implements GenTreePartModel { +public static final String rcsid = "$Id: GenTreeTestModel.java,v 1.1 2000/11/16 00:25:10 tjl Exp $"; + public static boolean dbg = true; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + public int depth() { + return 4; + } + + public int depth(ZZCell c) { + if(c.s("d.1") == null) + return -1; + // So the int it 0..3 + return Integer.parseInt(c.getText()); + } + + public ZZCell getNext(int mindepth, ZZCell c, int steps) { + if(steps == 0) return c; + c = c.s("d.1"); + int dir = (steps > 0 ? 1 : -1); + ZZCell lasthdr = null; + while(steps != 0 && c != null) { + c = c.s("d.2", dir); + if(c == null) return null; + lasthdr = c.s("d.1", -1); + if(lasthdr == null) continue; + if(depth(lasthdr) < mindepth) continue; + steps -= dir; + } + if(c == null) return null; + return lasthdr; + } + + public void disconnectNeg(ZZCell c) { + p("Model: disconnectneg "+c); + c.h("d.1", 1).disconnect("d.2", -1); + } + + public void connect(ZZCell c, ZZCell d) { + p("Model: connect "+c+" "+d); + c.h("d.1", 1).h("d.2", 1).connect("d.2", d.h("d.1", 1)); + } + + public void setDepth(ZZCell c, int d) { + if(depth(c) == 0) return; + c.setText(""+d); + } + +} diff --git a/Java/part/ImpliedTreePart.java b/Java/part/ImpliedTreePart.java new file mode 100644 index 0000000..d229c04 --- /dev/null +++ b/Java/part/ImpliedTreePart.java @@ -0,0 +1,173 @@ +/* +ImpliedTreePart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** EXPERIMENTAL: A tree implied by a sequence. + * A proof of concept of having a straight + * stream of material with "tags" connected next to it imply + * a tree. + *

    + * Connect a bunch of stuff on d.2 and add cells with numbers connected + * negwards on d.1, then view on imptree:depth and imptree:breadth + *

    + * The number is the level of the heading, reverse from HTML + * (1 is next to text, 2 is next above etc). + * For a heading of level N, N-1 cells are generated. + * The IDs of the generated cells are of the form + * k-ID where k is the level from the text up. + * So a heading of level 4 (cell ID 26) would have the following + * cells connected along depth: 26, i:3-26, i:2-26 and i:1-26. + *

    + * One problem of space parts: changing the section depth deletes cells, + * and cursors on those cells should be notified! + */ + +public class ImpliedTreePart extends ZZROStrSpacePart { +public static final String rcsid = "$Id: ImpliedTreePart.java,v 1.3 2000/11/13 11:59:32 tjl Exp $"; + + public ImpliedTreePart(ZZSpace space, String id) { + super(space, id); + } + + public String getText(ZZCellHandle c) { + return c.id.substring(c.id.length()-1); + } + + Depth dd = new Depth(); + Breadth db = new Breadth(); + + public ZZDimension getDim(String name) { + if(name.equals("depth")) return dd; + if(name.equals("breadth")) return db; + return null; + } + + public class Depth extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(steps == 0) return c; + + int level; + + if(c.part == ImpliedTreePart.this) { + int col = c.id.indexOf(":"); + int min = c.id.indexOf("-"); + level = Integer.parseInt(c.id.substring(col+1, min)); + c = (ZZCellHandle)this.space.getCellByID(c.id.substring(min+1)); + } else { + // It's either beginning or end of rank. + if(c.s("d.1", 1) != null) { + level = posno(c); + } else { + if(steps > 0) return null; + c = (ZZCellHandle)c.s("d.1", -1); + if(c == null) return null; + level = 0; + } + } + int maxlevel = posno(c); + if(maxlevel < 0) return null; + level -= steps; + if(level < 0) return null; + if(level == 0) return (ZZCellHandle)c.s("d.1", 1); + if(level > maxlevel) return null; + if(level == maxlevel) return c; + return ImpliedTreePart.this.space.getCellByID( + ImpliedTreePart.this, + level + "-" + c.id); + + } + } + + int posno(ZZCell c) { + try { + return Integer.parseInt(c.getText().trim()); + } catch(NumberFormatException e) { + ZZLogger.log("Not a number! '"+c.getText()+"' "+c+" "+e); + return -1; + } + } + + public class Breadth extends ZZDimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(steps == 0) return c; + ZZCell searchFrom; + int level; + if(c.part == ImpliedTreePart.this) { + int col = c.id.indexOf(":"); + int min = c.id.indexOf("-"); + level = Integer.parseInt(c.id.substring(col+1, min)); + c = (ZZCellHandle)this.space.getCellByID(c.id.substring(min+1)); + } else { + if(c.s("d.1", 1) == null) + return (ZZCellHandle)c.s("d.2", steps); + level = posno(c); + if(level < 0) return null; + } + searchFrom = c.s("d.1"); + if(searchFrom == null) return null; + + int dir = (steps > 0 ? 1 : -1); + int lastlevel = -1; + ZZCell lasthdr = null; + while(steps != 0) { + searchFrom = searchFrom.s("d.2", dir); + if(searchFrom == null) return null; + lasthdr = searchFrom.s("d.1", -1); + if(lasthdr == null) continue; + if((lastlevel = posno(lasthdr)) < level) continue; + steps -= dir; + } + + // Return our cell: the cell we ended up at is at higher level. + if(lastlevel > level) { + return ImpliedTreePart.this.space.getCellByID( + ImpliedTreePart.this, + level + "-" + lasthdr.getID()); + } else { + return (ZZCellHandle)lasthdr; + } + } + public void disconnect(ZZCellHandle c, int dir) { + if(dir > 0) { + ZZCellHandle c2 = s(c, 1); + if(c2 != null) + disconnect(c2, -1); + return; + } + ZZCell ct = dd.h(c, 1); + ct.disconnect("d.2", -1); + } + public void connect(ZZCellHandle c, ZZCellHandle d) { + if(s(c, 1) != null) + throw new ZZConnectWouldBreakError("In impliedtreedepth"); + if(s(d, -1) != null) + throw new ZZConnectWouldBreakError("In impliedtreedepth2"); + ZZCell c1 = dd.h(c, 1).h("d.2", 1); + ZZCell d1 = dd.h(d, 1).h("d.2", -1); + c1.connect("d.2", d1); + } + } + +} + diff --git a/Java/part/ImpliedTreePart2.java b/Java/part/ImpliedTreePart2.java new file mode 100644 index 0000000..3137857 --- /dev/null +++ b/Java/part/ImpliedTreePart2.java @@ -0,0 +1,192 @@ +/* +ImpliedTreePart2.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** EXPERIMENTAL: A tree implied by a sequence. + * Second version, to test the parsed space part stuff. + * A proof of concept of having a straight + * stream of material with "tags" connected next to it imply + * a tree. + *

    + * Connect a bunch of stuff on d.2 and add cells with numbers connected + * negwards on d.1, then view on imptree:depth and imptree:breadth + *

    + * The number is the level of the heading, reverse from HTML + * (1 is next to text, 2 is next above etc). + * For a heading of level N, N-1 cells are generated. + * The IDs of the generated cells are of the form + * k-ID where k is the level from the text up. + * So a heading of level 4 (cell ID 26) would have the following + * cells connected along depth: 26, i:3-26, i:2-26 and i:1-26. + *

    + * One problem of space parts: changing the section depth deletes cells, + * and cursors on those cells should be notified! + */ + +public class ImpliedTreePart2 extends ZZSpacePart { +public static final String rcsid = "$Id: ImpliedTreePart2.java,v 1.1 2000/11/13 11:59:48 tjl Exp $"; + + static public class Parsed { + String orig; + int depth; + } + + public ImpliedTreePart2(ZZSpace space, String id) { + super(space, id); + } + + public String getText(ZZCellHandle c) { + return c.id.substring(c.id.length()-1); + } + public void setContent(ZZCellHandle c, Object o) { + } + + public Object parseIDPart(String idPart) { + int min = idPart.indexOf("-"); + Parsed ret = new Parsed(); + ret.orig = idPart.substring(min+1); + ret.depth = Integer.parseInt(idPart.substring(0, min)); + return ret; + } + + public String generateIDPart(Object parsed) { + Parsed p = (Parsed)parsed; + return p.depth+"-"+p.orig; + } + + Depth dd = new Depth(); + Breadth db = new Breadth(); + + public ZZDimension getDim(String name) { + if(name.equals("depth")) return dd; + if(name.equals("breadth")) return db; + return null; + } + + public class Depth extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(steps == 0) return c; + + int level; + + if(c.part == ImpliedTreePart2.this) { + Parsed par = (Parsed)c.parsedID; + level = par.depth; + c = (ZZCellHandle)this.space.getCellByID(par.orig); + } else { + // It's either beginning or end of rank. + if(c.s("d.1", 1) != null) { + level = posno(c); + } else { + if(steps > 0) return null; + c = (ZZCellHandle)c.s("d.1", -1); + if(c == null) return null; + level = 0; + } + } + int maxlevel = posno(c); + if(maxlevel < 0) return null; + level -= steps; + if(level < 0) return null; + if(level == 0) return (ZZCellHandle)c.s("d.1", 1); + if(level > maxlevel) return null; + if(level == maxlevel) return c; + return ImpliedTreePart2.this.space.getCellByID( + ImpliedTreePart2.this, + level + "-" + c.id); + + } + } + + int posno(ZZCell c) { + try { + return Integer.parseInt(c.getText().trim()); + } catch(NumberFormatException e) { + ZZLogger.log("Not a number! '"+c.getText()+"' "+c+" "+e); + return -1; + } + } + + public class Breadth extends ZZDimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(steps == 0) return c; + ZZCell searchFrom; + int level; + if(c.part == ImpliedTreePart2.this) { + Parsed par = (Parsed)c.parsedID; + level = par.depth; + c = (ZZCellHandle)this.space.getCellByID(par.orig); + } else { + if(c.s("d.1", 1) == null) + return (ZZCellHandle)c.s("d.2", steps); + level = posno(c); + if(level < 0) return null; + } + searchFrom = c.s("d.1"); + if(searchFrom == null) return null; + + int dir = (steps > 0 ? 1 : -1); + int lastlevel = -1; + ZZCell lasthdr = null; + while(steps != 0) { + searchFrom = searchFrom.s("d.2", dir); + if(searchFrom == null) return null; + lasthdr = searchFrom.s("d.1", -1); + if(lasthdr == null) continue; + if((lastlevel = posno(lasthdr)) < level) continue; + steps -= dir; + } + + // Return our cell: the cell we ended up at is at higher level. + if(lastlevel > level) { + return ImpliedTreePart2.this.space.getCellByID( + ImpliedTreePart2.this, + level + "-" + lasthdr.getID()); + } else { + return (ZZCellHandle)lasthdr; + } + } + public void disconnect(ZZCellHandle c, int dir) { + if(dir > 0) { + ZZCellHandle c2 = s(c, 1); + if(c2 != null) + disconnect(c2, -1); + return; + } + ZZCell ct = dd.h(c, 1); + ct.disconnect("d.2", -1); + } + public void connect(ZZCellHandle c, ZZCellHandle d) { + if(s(c, 1) != null) + throw new ZZConnectWouldBreakError("In impliedtreedepth"); + if(s(d, -1) != null) + throw new ZZConnectWouldBreakError("In impliedtreedepth2"); + ZZCell c1 = dd.h(c, 1).h("d.2", 1); + ZZCell d1 = dd.h(d, 1).h("d.2", -1); + c1.connect("d.2", d1); + } + } + +} + diff --git a/Java/part/VersionPart.java b/Java/part/VersionPart.java new file mode 100644 index 0000000..28786b2 --- /dev/null +++ b/Java/part/VersionPart.java @@ -0,0 +1,634 @@ +/* +VersionPart.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag; +import java.util.*; + +/** EXPERIMENTAL: A space part showing past versions of a ZZCacheDimSpace. + */ + +public class VersionPart extends ZZROSpacePart { +public static final String rcsid = "$Id: VersionPart.java,v 1.15.2.1 2001/04/08 16:24:49 ajk Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + private static final Object nolla = new Object(); + + protected static final ZZObsTrigger ot = new ZZObsTrigger(); + + public static boolean regular_dimensions = false; + + protected Hashtable dimensions = new Hashtable(); + + protected String listDimensionName = "list"; + protected String activeDimensionName = "active"; + public VersionPart(ZZCacheDimSpace cds, String s) { + super(cds, s); + if (cds == null) throw new ZZError("null cds"); + dimensions.put(listDimensionName, new ListDimension()); + dimensions.put("home", new HomeDimension()); + dimensions.put(activeDimensionName, new ActiveDimension()); + dimensions.put("version-active", new ActiveCellVersionsDimension()); + } + + // spaces and stamps form a combined data structure where spaces + // provides fast lookup of SpaceElements based on space timestamps + // and stamps contains the active timestamps in ascending order. + private Hashtable spaces = new Hashtable(); + private Vector stamps = new Vector(); + + /** Show what's in stamps. This is a debugging method. */ + private void dump_stamps() { + if (!dbg) return; + + for (int i = 0; i < stamps.size(); i++) { + pa("stamps[" + i + "] == " + stamps.elementAt(i)); + } + } + + /** A set of data about one space. */ + private class SpaceElement { + /** The space timestamp. */ + Integer stampo; + /** Index of this SpaceElement in stamps. */ + int inx; + /** The space itself. */ + ZZCacheDimSpace space; + /** The cell that denotes this space in the version:list + * rank. */ + ZZDimSpace.DimCell cell; + + /** A cache of wrapper cells, keyed by unwrapped cell IDs, for + * this space. */ + private Hashtable wrappercells = new Hashtable(); + + /** A cache of wrapper dimensions, keyed by unwrapped + * dimension IDs, for this space. A key may map to "nolla", + * which means that the key does not denote an existing + * dimension. */ + private Hashtable wrapperdims = new Hashtable(); + + public void activate() { + if (space == null) { + space = new ZZCacheDimSpace((ZZCacheDimSpace)VersionPart.this.space, stampo.intValue()); + put(this); + } + } + + /** Get a wrapper cell for the cell "old". */ + public VersionCell getWrapperCell(ZZCellHandle old) { + return getWrapperCell(old, old.getID()); + } + + public VersionCell getWrapperCell(String oldid) { + return getWrapperCell((ZZCellHandle)space.getCellByID(oldid), oldid); + } + + public VersionCell getWrapperCell(ZZCellHandle old, String oldid) { + if (wrappercells.containsKey(oldid)) { + return (VersionCell)wrappercells.get(oldid); + } else { + VersionCell vc = new VersionCell(this, old); + wrappercells.put(oldid, vc); + return vc; + } + } + + /** Get a wrapper dimension for the dimension "dim". */ + public VersionDimension getWrapperDimension(String dim) { + if (wrapperdims.containsKey(dim)) { + Object o = wrapperdims.get(dim); + if (o == nolla) return null; + return (VersionDimension)o; + } else { + try { + wrapperdims.put(dim, new VersionDimension(this, dim)); + } catch (ZZError e) { + wrapperdims.put(dim, nolla); + } + return getWrapperDimension(dim); + } + } + + } + + /** Return a cell with this ID. */ + public ZZDimSpace.DimCell getCellByID(String s) { + ID id = (ID)parseIDPart(s); + SpaceElement se = getSpaceElement(id.stamp); + if (id.id == null) { + return se.cell; + } else { + se.activate(); + return se.getWrapperCell((ZZCellHandle)se.space.getCellByID(id.id)); + } + } + + /** Put se in spaces and update stamps. */ + private void put(SpaceElement se) { + synchronized (spaces) { + int i; + for (i = 0; i < stamps.size(); i++) { + if (((Integer)stamps.elementAt(i)).intValue() >= se.stampo.intValue()) break; + } + stamps.insertElementAt(se.stampo, i); + se.inx = i; + for (int j = i + 1; j < stamps.size(); j++) { + Integer stampo = (Integer)stamps.elementAt(j); + SpaceElement sep = (SpaceElement)spaces.get(stampo); + ++sep.inx; + } + spaces.put(se.stampo, se); + } + ot.chg(spaces); + } + + /** Get a SpaceElement corresponding to stamp. */ + protected SpaceElement getActiveSpaceElement(int stamp) { + return getActiveSpaceElement(new Integer(stamp)); + } + /** Get a SpaceElement corresponding to stampo and activate it. */ + protected SpaceElement getActiveSpaceElement(Integer stampo) { + synchronized (spaces) { + SpaceElement se = getSpaceElement(stampo); + se.activate(); + return se; + } + } + + /** Get a SpaceElement corresponding to stamp. */ + protected SpaceElement getSpaceElement(int stamp) { + return getSpaceElement(new Integer(stamp)); + } + + /** Get a SpaceElement corresponding to stampo. */ + protected SpaceElement getSpaceElement(Integer stampo) { + synchronized (spaces) { + if (spaces.containsKey(stampo)) { + return ((SpaceElement)spaces.get(stampo)); + } else { + SpaceElement se = new SpaceElement(); + se.inx = Integer.MAX_VALUE; + se.stampo = stampo; + se.space = null; + se.cell = new ListCell(se); + return se; + } + } + } + + + /** Return the space corresponding to stamp. */ + protected ZZCacheDimSpace getSpace(int stamp) { + return getActiveSpaceElement(stamp).space; + } + + /** Activate the space corresponding to stamp. */ + public void loadVersion(int stamp) { + if (stamp > ((ZZCacheDimSpace)space).timestamp) + stamp = ((ZZCacheDimSpace)space).timestamp; + getActiveSpaceElement(stamp); + } + + /** A parsed representation of a cell's or dimension's ID. */ + protected static class ID { + /** The wrapped dimension or cell's ID or null, if this is a list cell. */ + public final String id; + /** The space timestamp related to this cell or dimension. */ + public final int stamp; + + public ID(String id, int stamp) { + this.id = id; + this.stamp = stamp; + } + + public String toString() { + if (id == null) return "" + stamp; + return "" + stamp + "." + id; + } + } + + public ZZDimension getDim(String name) { + pa("VersionPart.getDim(" + name + ")"); + if (dimensions.containsKey(name)) return (ZZDimension)dimensions.get(name); + + if (name.substring(0, 2).equals("d.")) + return new AllVersionDimension(name); + + ID did = (ID)parseIDPart(name); + SpaceElement cds = getActiveSpaceElement(did.stamp); + + return cds.getWrapperDimension(did.id); + } + + /** A wrapper cell for cells in old space versions. */ + protected class VersionCell extends ZZDimSpace.DimCell { + final ZZCellHandle old; + + public VersionCell(SpaceElement se, ZZCellHandle old) { + VersionPart.this.space.super(VersionPart.this, + new ID(old.getID(), se.stampo.intValue())); + this.old = old; + } + + private boolean isIgnoredDim(String dim) { + return dim.equals("d.cursor") + || dim.equals("d.cursor-list") + || dim.equals("d.cursor-cargo") + || dim.indexOf(':') != -1; + } + + public ZZCell s(String dim, int dir, ZZObs o) { + ZZCell rv = s(dim, dir, o, new Object()); + p("(" + this + ").s(" + dim + ", " + dir + ", " + o + ") ==> " + rv); + return rv; + } + + private ZZCell s(String dim, int dir, ZZObs o, Object foo) { + if (!regular_dimensions || isIgnoredDim(dim)) + return super.s(dim, dir, o); + + // Connected in current version? If yes, use the connection. + ZZCell c = super.s(dim, dir, o); + if (c != null) return c; + + // No? Is there a connection in past active versions. + // If yes, use the newest. + synchronized (spaces) { + int n = stamps.size(); + for (int i = n - 1; i >= 0; --i) { + Integer stampo = (Integer)stamps.elementAt(i); + p("trying with " + stampo); + SpaceElement se = getActiveSpaceElement(stampo); + VersionDimension vd = se.getWrapperDimension(dim); + c = vd.s(this, dir, o); + if (c != null) return c; + } + } + + // No? Then there is no connection. + return null; + } + + public void disconnect(String dim, int dir) { + if (regular_dimensions && !isIgnoredDim(dim)) { + if (s(dim, dir, null) != null) { + throw new ZZError("immutable connection"); + } + } + + super.disconnect(dim, dir); + } + + + public void setText(String text) { + throw new ZZError("readonly cell"); + } + public void setSpan(Span text) { + throw new ZZError("readonly cell"); + } + public String getText(ZZObs o) { + return old.getText(o); + } + public Span getSpan(ZZObs o) { + return old.getSpan(o); + } + + public void delete() { + throw new ZZError("immutable cell"); + } + } + + /** A cell in the active spaces list. */ + protected class ListCell extends ZZDimSpace.DimCell { + SpaceElement se; + + public ListCell(SpaceElement se) { + VersionPart.this.space.super(VersionPart.this, + new ID(null, se.stampo.intValue())); + p("new ListCell, ID = " + getID()); + this.se = se; + } + + /** Create a new cell. If creating along version:list, we + * activate the next or previous space version. Otherwise we + * redelegate to the superclass. */ + public ZZCell N(String dim, int dir, ZZObs o, long flags) { + if (!dim.equals(VersionPart.this.id + ":" + activeDimensionName)) + return super.N(dim, dir, o, flags); + loadVersion(se.stampo.intValue() + dir); + return VersionPart.this.space.d(VersionPart.this.id + ":" + activeDimensionName).s(this, dir, o); + } + + public void setText(String text) { + throw new ZZError("readonly cell"); + } + public void setSpan(Span text) { + throw new ZZError("readonly cell"); + } + + public void delete() { + VersionPart.this.space.deleteCell(this); + se.space = null; + } + + } + + /** Dimension that lists all active versions. This dimension has + * funky semantics. First of all, there is always at most one + * nontrivial rank on this dimension. That rank's headcell is + * always the space homecell. The other cells are ListCells (ID + * of type "version:NUMBER") and they are listed on that rank in + * ascending numeric order on their content. The content always + * equals the NUMBER in the cell ID. If you connect some cell + * containing a number to this rank, the number is interpreted as + * a version and that version is activated. This means that + * instead of the cell appearing on that rank, a new cell appears + * in the right place and time. Disconnecting from this rank + * deactivates that version. One cannot connect to homecell's + * negative side or to other ranks on this dimension. */ + protected class ActiveDimension extends ZZDimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs obs) { + ZZCellHandle rv; + // inx will first denote the index of c in stamps; steps + // will then be added to it to make it point to the index + // in staps of the return value (or off-bounds if we want + // to return null) + int inx = Integer.MIN_VALUE; + try { + synchronized (spaces) { + if (c.equals(VersionPart.this.space.getHomeCell())) { + // home cell's posward neighbour is stamps[0] + inx = -1; + } else { + ID id = (ID)parseID(c.getID()); + if (id.id != null) { + // not a home cell or a ListCell, so we + // want to end up out of bounds + inx = -2-steps; + } else { + // this is a ListCell, look up the index in stamps + SpaceElement se = ((ListCell)c).se; + inx = se.inx; + } + } + // now inx will index the return value + inx += steps; + if (inx == -1) { + // stamps[0]'s negward neighbour is the home cell + rv = (ZZCellHandle)VersionPart.this.space.getHomeCell(); + } else if (inx == stamps.size()) { + // We're technically out of bounds, but this + // is sooo useful! We'll have the last + // committed version always as the tailcell. + // Its presence as the tailcell does not + // necessarily mean it's activated, however; + // we want it to remain unactivated after a + // new commit if it has not been examined, but + // also we want it to magically be active + // after a commit otherwise. + Integer stampo = new Integer(((ZZCacheDimSpace)VersionPart.this.space).timestamp); + // Careful here! If the tailcell version is + // active, it is stamps[stamps.size()-1] and + // thus we must not give it a posward + // neighbour that it is itself (that would + // break rank invariants) + if (spaces.containsKey(stampo)) + rv = null; + else { + // Okay, it's unactivated. + rv = getSpaceElement(stampo).cell; + } + } else if (inx < -1 || inx > stamps.size()) { + // off-bounds means no cigar + rv = null; + } else { + // within bounds, so this is straightforward + Integer stampo = (Integer)stamps.elementAt(inx); + rv = getSpaceElement(stampo).cell; + } + } + } catch (SyntaxError e) { + rv = null; + } + p("ActiveDimension.s(" + c + ", " + steps + ") (inx == " + inx + ", stamps.size() == " + stamps.size() + ") ==> " + rv); + dump_stamps(); + + if (obs != null) { ot.addObs(spaces, obs); } + + return rv; + } + + /** Is this cell a ListCell? */ + private boolean isOurs(ZZCellHandle c) { + return c.equals(VersionPart.this.space.getHomeCell()) + || (c.part == VersionPart.this + && ((ID)c.parsedID).id == null); + } + + /** "Connect" two cells on this dimension. This is rather + * magical, see the class documentation. */ + public void connect(ZZCellHandle c, ZZCellHandle d) { + pa("c = " + c + ", d = " + d); + if (isOurs(c) && isOurs(d)) return; // already on the rank + if (isOurs(c)) loadVersion(Integer.parseInt(d.getText())); + else if (isOurs(d)) loadVersion(Integer.parseInt(c.getText())); + else throw new ZZError("cannot connect those cells"); + dump_stamps(); + } + + /** "Disconnect" two cells on this dimension. This is rather + * magical, see the class documentation. */ + public void disconnect(ZZCellHandle c, int dir) { + synchronized (spaces) { + if (c.part != VersionPart.this || ((ID)c.parsedID).id != null) return; + Integer stampo = new Integer(((ID)c.parsedID).stamp); + if (!spaces.containsKey(stampo)) return; + SpaceElement se = (SpaceElement)spaces.get(stampo); + spaces.remove(stampo); + int n = stamps.size(); + stamps.removeElementAt(se.inx); + for (int i = se.inx; i < stamps.size(); i++) { + Integer stampone = (Integer)stamps.elementAt(i); + SpaceElement sese = getActiveSpaceElement(stampone); + sese.inx = i; + } + dump_stamps(); + } + } + + } + + protected class ListDimension extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs obs) { + ZZCellHandle home = (ZZCellHandle)VersionPart.this.space.getHomeCell(); + int i; + if (c.equals(home)) { + i = 0; + } else { + if (c.part != VersionPart.this) return null; + ID id = (ID)c.parsedID; + if (id.id != null) return null; + i = id.stamp; + } + i += steps; + if (!(0 <= i && i <= ((ZZCacheDimSpace)VersionPart.this.space).timestamp)) return null; + if (obs != null) ot.addObs(dimensions, obs); + if (i == 0) return home; + return getSpaceElement(i).cell; + } + } + + /** This dimension connects ListCells to their spaces' homecells.*/ + protected class HomeDimension extends ZZRODimension { + // note, this dimension never triggers anything as it is truly RO + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + synchronized (spaces) { + if (c.part != VersionPart.this) return null; + ID id = (ID)c.parsedID; + if (id.id != null) { + if (!getSpace(id.stamp).getHomeCell().getID().equals(id.id)) { + return null; + } + if (steps != -1) return null; + return getActiveSpaceElement(id.stamp).cell; + } + if (steps != 1) return null; + return ((ListCell)c). + se.getWrapperCell((ZZCellHandle)getSpace(id.stamp).getHomeCell()); + } + } + } + + /** This dimension wraps around dimensions in old space versions. */ + protected class VersionDimension extends ZZRODimension { + SpaceElement se; + ZZDimension old; + public VersionDimension(SpaceElement se, String dim) { + this.se = se; + Object o = se.space.d(dim); + if (o == null) throw new ZZError("no such dimension"); + old = (ZZDimension)o; + } + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + p("VersionDimension(" + se.stampo + ").s, c = " + c + ", c.part = " + c.part + ", c.getClass() = " + c.getClass()); + if (c.part != VersionPart.this) return null; + ID id = (ID)c.parsedID; + if (id.id == null) return null; + if (!(c instanceof VersionCell)) return null; + ZZCellHandle oldc = ((VersionCell)c).old; + if (id.stamp != se.stampo.intValue()) { + se.activate(); + oldc = (ZZCellHandle)se.space.getCellByID(c.getID()); + } + ZZCellHandle oldrc = old.s(oldc, steps, o); + p("oldc = " + oldc + ", oldrc = " + oldrc); + if (oldrc == null) return null; + return se.getWrapperCell(oldrc); + } + } + + protected class AllVersionDimension extends ZZRODimension { + String name; + public AllVersionDimension(String name) { + this.name = name; + } + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + if(c.part != VersionPart.this) + return (ZZCellHandle)c.s(name, steps, o); + ID id = (ID)c.parsedID; + if(id == null) + return (ZZCellHandle)c.s(name, steps, o); + return getActiveSpaceElement(id.stamp) + .getWrapperDimension(name) + .s(c, steps, o); + } + } + + protected class ActiveCellVersionsDimension extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs obs) { + synchronized (spaces) { + String cid; + int inx; + if (c.part == VersionPart.this) { + ID id = (ID)c.parsedID; + if (id.id == null) return null; + SpaceElement se_cur = getActiveSpaceElement(id.stamp); + inx = se_cur.inx; + cid = id.id; + } else if (c.part == null) { + inx = stamps.size(); + cid = c.getID(); + } else { + return null; + } + inx -= steps; + if (inx == stamps.size()) + return (ZZCellHandle)VersionPart.this.space.getCellByID(cid); + if (inx < 0 || inx > stamps.size()) + return null; + Integer stampo = (Integer)stamps.elementAt(inx); + SpaceElement se_new = getActiveSpaceElement(stampo); + if (obs != null) ot.addObs(spaces, obs); + return se_new.getWrapperCell(cid); + } + } + } + + public Object parseIDPart(String s) { + int idx = s.indexOf("."); + if (idx == s.length() -1) { + throw new SyntaxError("syntax error in cell/dimension ID: missing period"); + } + String id; + if (idx == -1) { + id = null; + idx = s.length(); + } else { + id = s.substring(idx+1); + } + int stamp; + try { + stamp = Integer.parseInt(s.substring(0, idx)); + } catch (NumberFormatException e) { + throw new SyntaxError("syntax error in cell/dimension ID: " + e.getMessage()); + } + return new ID(id, stamp); + } + + public String generateIDPart(Object parsed) { + String rv = ((ID)parsed).toString(); + p("VersionPart.generateIDPart returns " + rv); + return rv; + } + + public String getText(ZZCellHandle c) { + ID id = (ID)parseID(c.getID()); + if (id.id != null) { + return getSpace(id.stamp).getText(id.id); + } + return ""+id.stamp; + } + + public void postCommitHook() { ot.chg(dimensions); } + +} + diff --git a/Java/part/ZZROSpacePart.java b/Java/part/ZZROSpacePart.java new file mode 100644 index 0000000..d7ebb43 --- /dev/null +++ b/Java/part/ZZROSpacePart.java @@ -0,0 +1,39 @@ +/* +ZZROSpacePart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; + +/** EXPERIMENTAL: A read-only ZZSpacePart. + */ + +public abstract class ZZROSpacePart extends ZZSpacePart { +public static final String rcsid = "$Id: ZZROSpacePart.java,v 1.3 2000/11/06 12:39:39 tjl Exp $"; + + public ZZROSpacePart(ZZSpace space, String id) { + super(space, id); + } + + public void setContent(ZZCellHandle c, Object o) { + return; + } +} + diff --git a/Java/part/ZZROStrSpacePart.java b/Java/part/ZZROStrSpacePart.java new file mode 100644 index 0000000..2d75a03 --- /dev/null +++ b/Java/part/ZZROStrSpacePart.java @@ -0,0 +1,47 @@ +/* +ZZROStrSpacePart.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; + +/** EXPERIMENTAL: A read-only part of a ZZ space that only operates + * on IDs. + */ + +public abstract class ZZROStrSpacePart extends ZZROSpacePart { +public static final String rcsid = "$Id: ZZROStrSpacePart.java,v 1.3 2000/11/06 12:39:39 tjl Exp $"; + + public ZZROStrSpacePart(ZZSpace space, String id) { + super(space, id); + } + + public Object parseIDPart(String idPart) { + return null; + } + + public String generateID(Object parsed) { + return null; + } + public String generateIDPart(Object parsed) { + return null; + } +} + diff --git a/Java/script/Makefile b/Java/script/Makefile new file mode 100644 index 0000000..2397b86 --- /dev/null +++ b/Java/script/Makefile @@ -0,0 +1,53 @@ +PERLDIR=../../C++/script/Perl + + +IBMCFLAGS=-Dint64_t="long long" -Dlinux -g -I/BIG/ibmjdk/include -I/BIG/ibmjdk/include/linux -I../../C++ -I../../C++/script/Perl +CFLAGS=-g -I$(PERLDIR) + +IBMLDFLAGS=-L/BIG/ibmjdk/lib/linux/native_threads/ + +all: classes hdr jzigzag + +jzigzag: invoke.o zzfoo.o ZZScriptPerl.o ZZScriptAPI_1_JNI.o + gcc -o jzigzag -export-dynamic invoke.o zzfoo.o ZZScriptPerl.o ZZScriptAPI_1_JNI.o $(IBMLDFLAGS) -ljava `perl -MExtUtils::Embed -e ldopts` + +invoke.o: invoke.c + gcc $(IBMCFLAGS) -c invoke.c + +zzfoo.o: $(PERLDIR)/zzfoo.cpp + g++ $(CFLAGS) `perl -MConfig -e 'print "$$Config{ccflags} -I$$Config{installarchlib}/CORE"'` -c -o zzfoo.o -I../../C++ $(PERLDIR)/zzfoo.cpp + +ZZScriptPerl.o: ZZScriptPerl.cpp *.h + g++ $(IBMCFLAGS) -c -o ZZScriptPerl.o ZZScriptPerl.cpp + +ZZScriptAPI_1_JNI.o: ZZScriptAPI_1_JNI.cpp *.h + g++ $(IBMCFLAGS) -c -o ZZScriptAPI_1_JNI.o ZZScriptAPI_1_JNI.cpp + + +# all: classes hdr libZZScriptPerl.la + +classes: + javac -d .. *.java + +hdr: fi_iki_lukka_ZZScriptPerl.h + +fi_iki_lukka_ZZScriptPerl.h: ../fi/iki/lukka/ZZScriptPerl.class + javah -jni fi.iki.lukka.ZZScriptPerl + +# libZZScriptPerl.la: ZZScriptPerl.lo zzfoo.lo +# libtool g++ $(CFLAGS) -o libZZScriptPerl.la ZZScriptPerl.lo zzfoo.lo `perl -MConfig -e 'print "-L$$Config{installarchlib}/CORE -lperl $$Config{libs}"'` +# +# # Doesn't work due to DynaLoader! ARGH! +# #`perl -MExtUtils::Embed -e ccopts -e ldopts` +# +# zzfoo.lo: $(PERLDIR)/zzfoo.cpp +# libtool g++ $(CFLAGS) `perl -MConfig -e 'print "$$Config{ccflags} -I$$Config{installarchlib}/CORE"'` -c -o zzfoo.lo -I../../C++ $(PERLDIR)/zzfoo.cpp +# +# +# +# $(PERLDIR)/zzfoo.cpp: ../../C++/script/Perl/zzfoo.xs +# (cd $(PERLDIR); make zzfoo.cpp) +# +# +# ZZScriptPerl.lo: ZZScriptPerl.cpp *.h +# libtool g++ $(IBMCFLAGS) -c -o ZZScriptPerl.lo ZZScriptPerl.cpp diff --git a/Java/script/ZZId.h b/Java/script/ZZId.h new file mode 100644 index 0000000..94e346b --- /dev/null +++ b/Java/script/ZZId.h @@ -0,0 +1,12 @@ +#ifndef ZZID_H +#define ZZID_H + +// class _jobject; +// typedef _jobject* jobject; + +// #define ZZId jobject +// +// Arghh... +#define ZZId long + +#endif diff --git a/Java/script/ZZScriptAPI_1_JNI.cpp b/Java/script/ZZScriptAPI_1_JNI.cpp new file mode 100644 index 0000000..0ea5967 --- /dev/null +++ b/Java/script/ZZScriptAPI_1_JNI.cpp @@ -0,0 +1,31 @@ + +#include +#include "ZZId.h" +#include "ZZScriptAPI_1_JNI.h" +#include "zzfoo.h" + +const ZZScriptAPI_1_0_JNI::meth ZZScriptAPI_1_0_JNI::names[LASTMETH_] ; + /* + = { + { "getNeighbour", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "getHeadcell", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "newCell", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "delete", "()V" }, + { "connect", "(Ljava/lang/String;Lfi/iki/lukka/ZZCell;)V" }, + { "insert", "(Ljava/lang/String;ILfi/iki/lukka/ZZCell;)V" }, + { "disconnect", "(Ljava/lang/String;I)V" }, + { "getText", "()Ljava/lang/String;" }, + { "setText" "(Ljava/lang/String;)V" }, + }; */ + /* = { + { "getNeighbour", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "getHeadcell", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "newCell", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "delete", "()V" }, + { "connect", "(Ljava/lang/String;Lfi/iki/lukka/ZZCell;)V" }, + { "insert", "(Ljava/lang/String;ILfi/iki/lukka/ZZCell;)V" }, + { "disconnect", "(Ljava/lang/String;I)V" }, + { "getText", "()Ljava/lang/String;" }, + { "setText" "(Ljava/lang/String;)V" }, + }; */ + diff --git a/Java/script/ZZScriptAPI_1_JNI.h b/Java/script/ZZScriptAPI_1_JNI.h new file mode 100644 index 0000000..5f74cf9 --- /dev/null +++ b/Java/script/ZZScriptAPI_1_JNI.h @@ -0,0 +1,131 @@ +#ifndef ZZSCRIPT_API_1_JNI_H +#define ZZSCRIPT_API_1_JNI_H + +#define EXC() if(env->ExceptionOccurred()) {env->ExceptionDescribe(); env->FatalError("EXCEPTION");} + +// XXX ARGH +// #define MID(cell,id) (env->GetMethodID(env->GetObjectClass((jobject)cell), names[id].name, names[id].sig) || (env->FatalError("NoMethod"),(jmethodID)0)) +#define MID(cell,id) (env->GetMethodID(env->GetObjectClass((jobject)cell), names[id].name, names[id].sig)) + + +#include "ZZScriptAPI_1.h" + +class ZZScriptAPI_1_0_JNI : public ZZScriptAPI_1_0 { + protected: + JNIEnv *env; + jclass zzcell; + enum meths { + GETNEIGH, + HEADCELL, + NEWCELL, + DELETECELL, + CONNECTCELLS, + INSERTCELL, + DISCONNECT, + GETTEXT, + SETTEXT, + LASTMETH_ + }; + static const struct meth {char *name; char *sig;} names[LASTMETH_] + = { + { "getNeighbour", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "getHeadcell", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "newCell", "(Ljava/lang/String;I)Lfi/iki/lukka/ZZCell;" }, + { "delete", "()V" }, + { "connect", "(Ljava/lang/String;Lfi/iki/lukka/ZZCell;)V" }, + { "insert", "(Ljava/lang/String;ILfi/iki/lukka/ZZCell;)V" }, + { "disconnect", "(Ljava/lang/String;I)V" }, + { "getText", "()Ljava/lang/String;" }, + { "setText", "(Ljava/lang/String;)V" }, + }; + jmethodID mids[LASTMETH_]; + public: + ZZScriptAPI_1_0_JNI(JNIEnv *env0) { + utfref = 0; + strref = 0; + env = env0; + zzcell = env->FindClass("fi/iki/lukka/ZZCell"); + if(!zzcell) abort(); + zzcell = (jclass)env->NewGlobalRef(zzcell); + if(!zzcell) abort(); + for(int i=0; iGetMethodID(zzcell, names[i].name, names[i].sig); + if(!mids[i]) { + abort(); + } + } + } + + static const int verbose = 1; + + virtual ZZId get_cell (ZZId from, const char *dim, int dir) { + printf("CB GETCELL\n"); + long res = (long)env->CallObjectMethod((jobject)from, MID(from,GETNEIGH), + env->NewStringUTF(dim), (jint)dir); + EXC(); + return res; + }; + virtual ZZId get_headcell (ZZId from, const char *dim, int dir) + { + printf("CB HEADCELL\n"); + EXC(); + abort(); + }; + virtual ZZId new_cell (ZZId from, const char *dim, int dir) { + printf("CB NEWCELL\n"); + long res = (long)env->CallObjectMethod((jobject)from, MID(from,NEWCELL), + env->NewStringUTF(dim), (jint)dir); + EXC(); + return res; + } + virtual void delete_cell (ZZId cell) { + printf("CB DELCELL\n"); + env->CallVoidMethod((jobject)cell, MID(cell,DELETECELL)); + EXC(); + }; + virtual void connect_cells (ZZId from, const char *dim, ZZId to) { + printf("CB CONCELL\n"); + env->CallVoidMethod((jobject)from, MID(from,CONNECTCELLS), + env->NewStringUTF(dim), (jobject)to); + EXC(); + }; + virtual void insert_cell (ZZId where, const char *dim, int dir, ZZId what) { + printf("CB INSCELL\n"); + env->CallVoidMethod((jobject)where, MID(where,INSERTCELL), + env->NewStringUTF(dim), (jint)dir, (jobject)what); + EXC(); + }; + virtual void disconnect (ZZId from, const char *dim, int dir) { + printf("CB DISCELL\n"); + env->CallVoidMethod((jobject)from, MID(from,NEWCELL), + env->NewStringUTF(dim), (jint)dir); + EXC(); + }; + const char *utfref; + jstring strref; + virtual const char *get_text (ZZId cell) { + printf("CB GETTEXT\n"); + if(utfref) { + // XXX? + env->ReleaseStringUTFChars(strref, utfref); + } + strref = (jstring)env->CallObjectMethod((jobject)cell, MID(cell,GETTEXT)); + utfref = env->GetStringUTFChars(strref,0); + EXC(); + return utfref; + }; + virtual void set_text (ZZId cell, const char *str) { + printf("CB SETTEXT\n"); + env->CallVoidMethod((jobject)cell, MID(cell,SETTEXT), + env->NewStringUTF(str)); + EXC(); + printf("CB SETTEXT ret\n"); + }; + virtual int popup_warning (const char *text) { + abort(); + }; + + +}; + +#endif diff --git a/Java/script/ZZScriptPerl.cpp b/Java/script/ZZScriptPerl.cpp new file mode 100644 index 0000000..c17c867 --- /dev/null +++ b/Java/script/ZZScriptPerl.cpp @@ -0,0 +1,55 @@ +#include +#include "ZZId.h" +#include "ZZScriptAPI_1_JNI.h" +#include "zzfoo.h" + +static jclass zzspclass; +static jfieldID ptrid; + +extern "C" { +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZScriptPerl_init + (JNIEnv *env, jobject foo) +{ + if(!zzspclass) + zzspclass = (jclass)env->NewGlobalRef(env->GetObjectClass(foo)); + ptrid = env->GetFieldID(zzspclass, "ptr", "J"); + if(!ptrid) abort(); + ZZScriptAPI_1_0_JNI *j = new ZZScriptAPI_1_0_JNI(env); + zzperl_init(j); + env->SetLongField(foo, ptrid, (jlong)j); +} + +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZScriptPerl_call + (JNIEnv *env, jobject foo, jstring code0, jobject view0, jobject + cview0, jobject scr0, jobject cur0, jstring dimx0, jstring dimy0) +{ + printf("ENTERING PERLCALL\n"); + ZZScriptAPI_1_0_JNI *j = (ZZScriptAPI_1_0_JNI *) env->GetLongField(foo, ptrid); + if(!j) abort(); + char *code = (char *)env->GetStringUTFChars(code0, 0); + char *dimx = (char *)env->GetStringUTFChars(dimx0, 0); + char *dimy = (char *)env->GetStringUTFChars(dimy0, 0); + + zzperl_call(code, (long)view0, (long)cview0, (long)scr0, (long)cur0, dimx, dimy); + + env->ReleaseStringUTFChars(code0,code); + env->ReleaseStringUTFChars(dimx0,dimx); + env->ReleaseStringUTFChars(dimy0,dimy); + printf("RETURNING FROM PERLCALL\n"); + +} + +JNINativeMethod ms[2] = { +{ "init", "()V", Java_fi_iki_lukka_ZZScriptPerl_init }, +{ "call", "(Ljava/lang/String;Lfi/iki/lukka/ZZCell;Lfi/iki/lukka/ZZCell;Lfi/iki/lukka/ZZCell;Lfi/iki/lukka/ZZCell;Ljava/lang/String;Ljava/lang/String;)V", +Java_fi_iki_lukka_ZZScriptPerl_call } +}; + +void zsp_install(JNIEnv *env) { + zzspclass = env->FindClass("fi/iki/lukka/ZZScriptPerl"); + if(!zzspclass) abort(); + zzspclass = (jclass)env->NewGlobalRef(zzspclass); + env->RegisterNatives(zzspclass, ms, 2); +} + +} diff --git a/Java/script/ZZScriptPerl.java b/Java/script/ZZScriptPerl.java new file mode 100644 index 0000000..58ec097 --- /dev/null +++ b/Java/script/ZZScriptPerl.java @@ -0,0 +1,9 @@ +package org.gzigzag; + +public class ZZScriptPerl { + long ptr; + public ZZScriptPerl() { init(); }; + public native void init(); + public native void call(String code, ZZCell view, ZZCell controlView, + ZZCell script, ZZCell cur, String dimX, String dimY); +} diff --git a/Java/script/invoke.c b/Java/script/invoke.c new file mode 100644 index 0000000..2849ae6 --- /dev/null +++ b/Java/script/invoke.c @@ -0,0 +1,76 @@ +// Copied from +// http://java.sun.com/docs/books/tutorial/native1.1/invoking/example-1dot1/invoke.c + +#include + +#ifdef _WIN32 +#define PATH_SEPARATOR ';' +#else /* UNIX */ +#define PATH_SEPARATOR ':' +#endif + +// #define USER_CLASSPATH "." /* where Prog.class is */ + +extern void zsp_install(JNIEnv *env); + +main() { + JNIEnv *env; + JavaVM *jvm; + JDK1_1InitArgs vm_args; + jint res; + jclass cls; + jmethodID mid; + jstring jstr; + jobjectArray args; + char classpath[1024]; + + + /* IMPORTANT: specify vm_args version # if you use JDK1.1.2 and beyond */ + vm_args.version = 0x00010001; + + JNI_GetDefaultJavaVMInitArgs(&vm_args); + // Tjl + vm_args.classpath = getenv("CLASSPATH"); + +// /* Append USER_CLASSPATH to the end of default system class path */ +// sprintf(classpath, "%s%c%s", +// vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH); +// vm_args.classpath = classpath; + + /* Create the Java VM */ + res = JNI_CreateJavaVM(&jvm,&env,&vm_args); + if (res < 0) { + fprintf(stderr, "Can't create Java VM\n"); + exit(1); + } + + zsp_install(env); + + cls = (*env)->FindClass(env, "foo/Test1"); + if (cls == 0) { + fprintf(stderr, "Can't find foo/Test1 class\n"); + exit(1); + } + + mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V"); + if (mid == 0) { + fprintf(stderr, "Can't find Prog.main\n"); + exit(1); + } + + jstr = (*env)->NewStringUTF(env, " from C!"); + if (jstr == 0) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + args = (*env)->NewObjectArray(env, 1, + (*env)->FindClass(env, "java/lang/String"), jstr); + if (args == 0) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + (*env)->CallStaticVoidMethod(env, cls, mid, args); + + (*jvm)->DestroyJavaVM(jvm); +} + diff --git a/Java/storage/ContentStore.java b/Java/storage/ContentStore.java new file mode 100644 index 0000000..1f027b6 --- /dev/null +++ b/Java/storage/ContentStore.java @@ -0,0 +1,35 @@ +/* +ContentStore.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** An interface for storing contents info in. + * The Objects are supposed to be either String or Span type. + */ + +public interface ContentStore { +String rcsid = "$Id: ContentStore.java,v 1.4 2000/09/19 10:32:00 ajk Exp $"; + void put(String id1, Object what); + Object get(String id); +} + diff --git a/Java/storage/ContentStorer.java b/Java/storage/ContentStorer.java new file mode 100644 index 0000000..86b234d --- /dev/null +++ b/Java/storage/ContentStorer.java @@ -0,0 +1,36 @@ +/* +ContentStore.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** An interface for storing contents info. + * The difference with ContentStore is that this is analogous to + * ZZDimStorer whereas ContentStore is more like ZZDimension. + * The Objects are supposed to be either String or Span type. + */ + +public interface ContentStorer { +String rcsid = "$Id: ContentStorer.java,v 1.3 2000/09/19 10:32:00 ajk Exp $"; + void putContent(String id, Object what); +} + diff --git a/Java/storage/CountingStream.java b/Java/storage/CountingStream.java new file mode 100644 index 0000000..7edbb3b --- /dev/null +++ b/Java/storage/CountingStream.java @@ -0,0 +1,71 @@ +/* +CountingStream.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** Something Java should have: we conut our position in the stream. + */ + +public class CountingStream extends FilterInputStream { + + int curPos = 0; + + public CountingStream(InputStream is) { + super(is); + } + + public int read() throws IOException { + int c = super.read(); + curPos++; + return c; + } + + public int read(byte b[]) throws IOException { + int n = super.read(b); + if(n < 0) return n; + curPos += n; + return n; + } + + public int read(byte b[], + int off, + int len) throws IOException { + int n = super.read(b, off, len); + if(n < 0) return n; + curPos += n; + return n; + } + + public long skip(long n) throws IOException { + long ns = super.skip(n); + curPos += ns; + return ns; + } + + public int getCount() { + return curPos; + } + +} diff --git a/Java/storage/DimStore.java b/Java/storage/DimStore.java new file mode 100644 index 0000000..d4bc5f9 --- /dev/null +++ b/Java/storage/DimStore.java @@ -0,0 +1,33 @@ +/* +DimStore.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** An interface for storing dimension info in. + */ + +public interface DimStore { +String rcsid = "$Id: DimStore.java,v 1.3 2000/09/19 10:32:00 ajk Exp $"; + void put(String id1, String id2); + String get(String id, int dir); +} diff --git a/Java/storage/DirStreamSet.java b/Java/storage/DirStreamSet.java new file mode 100644 index 0000000..8833ccc --- /dev/null +++ b/Java/storage/DirStreamSet.java @@ -0,0 +1,91 @@ +/* +DirStreamSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka, locking by Antti-Juhani Kaijanaho + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A directory implementation of StreamSet + */ + +public class DirStreamSet extends StreamSet { +public static final String rcsid = "$Id: DirStreamSet.java,v 1.5 2000/09/18 14:28:22 tjl Exp $"; + File dir; + + public InputStream getInputStream(String id) { + try { + File f = new File(dir, id); + if(!f.exists()) return null; + if(!f.canRead()) throw new ZZFatalError("Can't read file"); + return new BufferedInputStream( + new FileInputStream(f), 4096); + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZFatalError("File problem"); + } + } + + public OutputStream getAppendStream(String id) { + try { + File f = new File(dir, id); + return new BufferedOutputStream( + new FileOutputStream(f.getPath(), true)); + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZFatalError("File problem"); + } + } + public boolean exists(String id) { + File fn = new File(dir, id); + return fn.exists(); + } + + public Writable getWritable(String id) { + if(id == null || id.equals("")) + throw new ZZError("Can't use writables with null or empty name"); + try { + File fn = new File(dir, id); + final RandomAccessFile f = new RandomAccessFile(fn, "rw"); + return new FileWritable(f) ; + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" "+e); + } + } + + public DirStreamSet(File dir0) { + try { + dir = dir0; + if(dir.exists() && !dir.isDirectory()) { + throw new ZZError("MUST BE DIRECTORY!!!! "+dir); + } + if(!dir.exists()) { + dir.mkdirs(); + } + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" "+e); + } + } +} + + diff --git a/Java/storage/DummyStreamSet.java b/Java/storage/DummyStreamSet.java new file mode 100644 index 0000000..f2afe8c --- /dev/null +++ b/Java/storage/DummyStreamSet.java @@ -0,0 +1,50 @@ +/* +DummyStreamSet.java + * + * Copyright (c) 1999-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; + +import java.awt.*; +import java.applet.*; +import java.io.*; +import java.util.*; + +/** A dummy stream set for ZZ spaces. + * Save fails, mostly for applets and testing. + */ + +public class DummyStreamSet extends StreamSet { + public InputStream getInputStream(String id) { return null; } + public OutputStream getAppendStream(String id) { return null; } + public boolean exists(String id) { return false; } + + Hashtable ws = new Hashtable(); + public Writable getWritable(String id) { + Writable res = (Writable)ws.get(id); + if(res == null) { + res = new MemWritable(); + ws.put(id, res); + } + return res; + } +} + diff --git a/Java/storage/FileWritable.java b/Java/storage/FileWritable.java new file mode 100644 index 0000000..7c1c250 --- /dev/null +++ b/Java/storage/FileWritable.java @@ -0,0 +1,251 @@ +/* +FileWritable.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka & Vesa Parkkinen + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A Writable that is just a file. + * + * Default: caching off.. + */ + +// Beginning of block: +// long: index of next block +// long: offset in subfile0 to the name. + +public class FileWritable implements Writable { + public static final String rcsid = + "$Id: FileWritable.java,v 1.6 2000/09/19 10:32:00 ajk Exp $"; + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + public static final int BUF_SIZE = 512; + + RandomAccessFile f; + + byte[] r_buffer; + byte[] w_buffer; + + boolean cache; + boolean dirty; + + // read buffer offset + long off; + // write buffer offset + long w_off; + // read bytes in buffer + int r_size; + // bytes written + int written; + + /* + * XXX TODO: not quite there yet... + */ + public void write(long offset, byte[] data) { + //p("write"); + try { + if( ! cache ){ + f.seek(offset); + f.write(data); + return; + }else { + // clear read cache + if ( offset < off + r_size && + offset + data.length > off ) { + + off = 0; + r_size = 0; + } + + if ( data.length > BUF_SIZE ){ + //p(" > "); + flush(); + f.seek(offset); + f.write(data); + return; + } + if ( offset + data.length < w_off ){ + //p(" under "); + f.seek(offset); + f.write(data); + //return; + }else if ( offset > w_off + written ){ + //p(" over "); + flush(); + w_off = offset; + written = data.length; + System.arraycopy( data, 0, w_buffer, 0, written ); + dirty = true; + }else if ( offset < w_off && offset + data.length > w_off ){ + //p(" partial "); + flush(); + f.seek(offset); + f.write(data); + + } else if( offset == w_off + written && + BUF_SIZE - written > data.length ) { + //p(" hit: " + offset); + System.arraycopy( data, 0, w_buffer, written, data.length); + written += data.length; + //p(" written = " + written); + dirty = true; + }else { + //p(" other "); + flush(); + f.seek(offset); + f.write(data); + return; + } + + } + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" "+e); + } + } + + + public byte[] read(long offset, int n) { + //p("read"); + try { + + byte[] b = new byte[n]; + + if( ! cache ){ + f.seek(offset); + f.read(b); + return b; + } else { + if( offset < w_off + written && + offset + n > w_off ) { + flush(); + } + if ( offset > off && offset - off + n < r_size ){ + + System.arraycopy(r_buffer, (int)(offset - off), b, 0, n ); + return b; + } + + f.seek(offset); + + r_size = f.read(r_buffer); + System.arraycopy(r_buffer, 0, b, 0, n ); + off = offset; + return b; + } + + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" read "+offset+" "+n+" "+e); + } + } + + + public void read(long offset, byte b[], int o, int n) { + //p("read2"); + try { + if (! cache ){ + f.seek(offset); + f.read(b, o, n); + }else { + if( offset + o < w_off + written && + offset + o + n > w_off ) { + flush(); + } + + if ( offset + o> off && offset + o - off + n < r_size ){ + + System.arraycopy(r_buffer, (int)(offset + o - off), + b, o, n ); + }else { + f.seek(offset + o); + r_size = f.read(r_buffer); + System.arraycopy(r_buffer, 0, b, o, n ); + off = offset + o; + } + } + + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" read " +e); + } + + } + + public long length() { + try { + return f.length(); + + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" "+e); + } + } + + + public void flush() { + if ( ! cache ) return; + if( ! dirty || written == 0) return; + + try{ + + f.seek(w_off); + f.write(w_buffer, 0, written); + dirty = false; + //p("FLUSH " + written); + written = 0; + + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError(" "+e); + } + + } + + public FileWritable(RandomAccessFile f) { + + /* + * set this to true, if you want to test caching + */ + this(f, false); + } + + public FileWritable(RandomAccessFile f, boolean b) { + //p("FW: create"); + this.f = f; + cache = b; + + if ( cache ){ + r_buffer = new byte[BUF_SIZE]; + w_buffer = new byte[BUF_SIZE]; + }else{ + r_buffer = null; + } + dirty = false; + r_size = 0; + } +} + + + diff --git a/Java/storage/Flushable.java b/Java/storage/Flushable.java new file mode 100644 index 0000000..d5e847f --- /dev/null +++ b/Java/storage/Flushable.java @@ -0,0 +1,39 @@ +/* +Flushable.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** An interface for things that can be flushed. + * Mostly for determining if e.g. a ZZSpace needs flushing. + */ + +public interface Flushable { +String rcsid = "$Id: Flushable.java,v 1.3 2000/09/19 10:32:00 ajk Exp $"; + /** Flush the contents not yet flushed to disk. + */ + void flush(); + /** Whether this object is in fact in a cache-keeping mode. + */ + boolean isCaching(); +} + diff --git a/Java/storage/GZZ0.java b/Java/storage/GZZ0.java new file mode 100644 index 0000000..dc28667 --- /dev/null +++ b/Java/storage/GZZ0.java @@ -0,0 +1,191 @@ +/* +GZZ0.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.io.*; + +/** An implementation of the GZZ0 file format. + */ + +public class GZZ0 { +String rcsid = "$Id: GZZ0.java,v 1.7 2001/03/01 13:53:53 ajk Exp $"; + public static boolean dbg = false; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + final int magic = 0x475a5a30; // "GZZ0" + final int version = 0; + final byte rTime = 116; + + public interface Runner { + /** Returns the GZZ0 content type of this runner. + */ + int getContentType(); + /** Returns the GZZ0 content version of this runner. + */ + int getContentVersion(); + /** Read a run. + */ + void readRun(InputStream is); + /** Start writing. + */ + void startWrite(OutputStream os); + /** Finish writing. + */ + void endWrite(); + + } + + StreamSet ss; + String id; + + public GZZ0(StreamSet ss, String id) { + this.ss = ss; this.id = id; + } + + /** Read the latest dataset into the given runner. + * @param r The runner into which to give the runs + * @param maxtimestamp The maximum timestamp whose changes to include. + * @return The latest timestamp read. + */ + public int read(Runner r, int maxtimestamp) { + InputStream is = ss.getInputStream(id); + CountingStream counts = null; + if(dbg) { + is = counts = new CountingStream(is); + } + DataInputStream dis = new DataInputStream(is); + + // Read header + try { + int i = dis.readInt(); + if(i != magic) + throw new ZZFatalError("Invalid file format! Doesn't begin with GZZ0 magic"); + i = dis.readInt(); + if(i != version) + throw new ZZFatalError("Invalid file version! Not "+version); + i = dis.readInt(); + if(i != r.getContentType()) + throw new ZZFatalError("Wrong content type!"); + i = dis.readInt(); + if(i != r.getContentVersion()) + throw new ZZFatalError("Wrong content version!"); + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + + // Read body. + + int lastTime = -1; + boolean eofOk = true; + byte[] byt = new byte[4096]; + try { + while(true) { + eofOk = true; + byte rectype = dis.readByte(); + eofOk = false; + if(rectype != rTime) + throw new ZZFatalError("Invalid timestamp record! " + id + " " + + (counts != null ? counts.getCount() : -1)); + lastTime = dis.readInt(); + int nbytes = dis.readInt(); + + if(maxtimestamp > 0 && lastTime > maxtimestamp) { + dis.close(); + return lastTime; + } + + if(nbytes > byt.length) + byt = new byte[nbytes]; + + dis.readFully(byt, 0, nbytes); + ByteArrayInputStream bis = + new ByteArrayInputStream(byt, 0, nbytes); + r.readRun(bis); + } + } catch(EOFException e) { + if(!eofOk) + throw new ZZFatalError("Unexpected eof in simpledimfile"); + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + return lastTime; + } + + ByteArrayOutputStream outputStream; + DataOutputStream dos; + Runner runner; + int timestamp; + + /** Write the changes back. + * XXX Should check runner's type... + */ + public void startWrite(int timestamp, Runner r) { + + outputStream = new ByteArrayOutputStream(); + this.timestamp = timestamp; + this.runner = r; + + runner.startWrite(new DataOutputStream(outputStream)); + } + + /** Finish writing. */ + public void endWrite(boolean forceStamp) { + boolean ex = ss.exists(id); + runner.endWrite(); + + try { + OutputStream os = ss.getAppendStream(id); + dos = new DataOutputStream(os); + if(!ex) { + // Write header. + dos.writeInt(magic); + dos.writeInt(version); + dos.writeInt(runner.getContentType()); + dos.writeInt(runner.getContentVersion()); + dos.flush(); + } + byte[] byt = outputStream.toByteArray(); + if(byt.length == 0 && !forceStamp) { + pa("Not writing "+id); + return; + } + pa("Writing "+id+" "+byt.length); + + dos.writeByte(rTime); + dos.writeInt(timestamp); + dos.writeInt(byt.length); + dos.write(byt); + dos.flush(); + dos = null; + outputStream = null; + runner = null; + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Writing file"); + } + } + +} diff --git a/Java/storage/MemWritable.java b/Java/storage/MemWritable.java new file mode 100644 index 0000000..b882c4d --- /dev/null +++ b/Java/storage/MemWritable.java @@ -0,0 +1,76 @@ +/* +MemWritable.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag; +import java.util.*; + +/** A writable that stores its contents in memory. + * Used to make scrolls work in applets. Not necessarily very efficient; + * however, I don't think that's so much of an issue in applets, where we + * won't save a lot of data anyway. + */ + +public class MemWritable implements Writable { +String rcsid = "$Id: MemWritable.java,v 1.1 2000/12/26 22:48:37 bfallenstein Exp $"; + + /** The size of the chunks in which memory is allocated. */ + final int CHUNK = 500; + + /** The data. */ + byte[] d = new byte[CHUNK]; + + /** The length of the data actually used. + * len-1 is the highest index of any data ever written. + */ + int len = 0; + + public void extend() { + byte[] nu = new byte[d.length + CHUNK]; + System.arraycopy(d, 0, nu, 0, len); + d = nu; + } + + public void write(long offset0, byte[] data) { + int offset = (int)offset0; + int n = data.length; + while(offset + n >= d.length) extend(); + System.arraycopy(data, 0, d, offset, n); + if(offset + n > len) len = offset + n; + } + public byte[] read(long offset0, int n) { + byte[] res = new byte[n]; + read(offset0, res, 0, n); + return res; + } + public void read(long offset0, byte b[], int off, int n){ + System.out.println("MemWritable.read "+d.length+" "+len+" params "+ + offset0+" "+b.length+" "+off+" "+n); + int offset = (int)offset0; + while(offset + n >= d.length) extend(); + System.arraycopy(d, offset, b, off, n); + } + public long length() { + return len; + } + public void flush() {} +} + diff --git a/Java/storage/Recs.pl b/Java/storage/Recs.pl new file mode 100644 index 0000000..07dd0b9 --- /dev/null +++ b/Java/storage/Recs.pl @@ -0,0 +1,232 @@ +# +# $Id: Recs.pl,v 1.8 2001/03/06 13:44:39 ajk Exp $ +# +# Generate Recs.java for record types for file formats. +# +# Java Serializable is CLOSE but not quite close enough to what we need +# (e.g. it would write out the "offset" field) +# AND we want a standard binary format. + + +$file = $ARGV[0]; +$file = "Recs.pl" if ($file eq ""); +open F, ">$file" or die "Can't open file $file"; +$rcsid = '$Id: Recs.pl,v 1.8 2001/03/06 13:44:39 ajk Exp $'; +print F <[2]; + my $len = join '+', + " super.length() ", + map { + $_->[0] eq "long" and 8 + or $_->[0] eq "int" and 4 + or $_->[0] eq "short" and 2 + or $_->[0] eq "boolean" and 1 + or $_->[0] eq "String" and + " (2 + $_->[1].getBytes(\"UTF8\").length) " + or die "Invalid type $_->[0]" + } @f; + + my $write = join '', + map { + $_->[0] eq "String" and + "{ + byte[] bt = $_->[1].getBytes(\"UTF8\"); + s.writeShort(bt.length); + s.write(bt, 0, bt.length); + } + " + # or $_->[0] eq "bool" and "s.writeBoolean($_->[1]);" + or "s.write".(ucfirst $_->[0])."($_->[1]);"; + } @f; + + my $read = join '', + map { + $_->[0] eq "String" and + "{ + short l = s.readShort(); + byte[] bt = new byte[l]; + int n = s.read(bt); + if(n!=l) throw new ZZError(\"NOT ENOUGH DATA\"); + $_->[1] = new String(bt, \"UTF8\"); + } + " + # or $_->[0] eq "bool" and "$_->[1] = s.readBoolean();" + or "$_->[1] = s.read".(ucfirst $_->[0])."();"; + } @f; + + my $tostring = join '', + map { + qq( + " $_->[1]: "+$_->[1]+"\\n" ) + } @f; + + + print F <[0] extends $_->[1] { + $_->[2]; + public int length() { + try { + return $len; + } catch(Exception e) { + ZZLogger.exc(e); + throw new ZZError("ARGH"); + } + } + public short getTypeNo() { return $_->[3]; } + public void write_data(DataOutputStream s) throws IOException { + super.write_data(s); + $write + } + public void read_data(long offs, DataInputStream s) + throws IOException { + super.read_data(offs, s); + $read + } + public String toString() { + return "$_->[0]:\\n" + $tostring + + super.toString(); + } + } +END +} + +print F qq[ + static public Record createRecord(int typ) { + $rettype + throw new ZZError("Invalid record type "+typ); + } +} +]; diff --git a/Java/storage/SimpleContentFile.java b/Java/storage/SimpleContentFile.java new file mode 100644 index 0000000..f5ffc10 --- /dev/null +++ b/Java/storage/SimpleContentFile.java @@ -0,0 +1,129 @@ +/* +SimpleContentFile.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A simple content file format. + * The format consists of records: s(cell)(string), S(cell)(span), + * t(time4). Currently spans are stored in their stringized format + * but this may be changed later. + *

    + * The record types are defined by the ASCII values of the above characters. + *

    + * Note the similarity with SimpleDimFile. + */ + +public class SimpleContentFile implements ContentStorer, GZZ0.Runner { +public static final String rcsid = "$Id: SimpleContentFile.java,v 1.6 2000/09/19 10:32:00 ajk Exp $"; + + final byte rString = 115; + final byte rSpan = 83; + + ContentStorer sto; + public void startRead(ContentStorer sto) { + this.sto = sto; + } + public void endRead() { + sto = null; + } + + public int getContentType() { + return 43; + } + public int getContentVersion() { + return 0; + } + + + public void readRun(InputStream is) { + DataInputStream dis = new DataInputStream(is); + boolean eofOk = true; + try { + while(true) { + eofOk = true; + byte rectype = dis.readByte(); + eofOk = false; + switch(rectype) { + case rString: { + String id = dis.readUTF(); + String ct = dis.readUTF(); + sto.putContent(id, ct); } + break; + case rSpan: { + String id = dis.readUTF(); + String cts = dis.readUTF(); + Span sp = Span.parse(cts); + sto.putContent(id, sp); } + break; + default: + throw new ZZFatalError("Invalid record"); + } + } + } catch(EOFException e) { + if(!eofOk) + throw new ZZError("Unexpected eof in simpledimfile"); + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + } + + DataOutputStream dos; + + public void putContent(String id, Object ct) { + if(ct == null) + throw new ZZFatalError("Tried to store null content!"); + try { + if(ct instanceof String) { + dos.writeByte(rString); + dos.writeUTF(id); + dos.writeUTF((String)ct); + } else if(ct instanceof Span) { + dos.writeByte(rSpan); + dos.writeUTF(id); + dos.writeUTF(((Span)ct).toString()); + } else { + throw new ZZFatalError("Can't put odd object: "+ct); + } + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + } + + public void startWrite(OutputStream dos) { + this.dos = new DataOutputStream(dos); + } + + public void endWrite() { + try { + dos.flush(); + dos = null; + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + } + +} diff --git a/Java/storage/SimpleDimFile.java b/Java/storage/SimpleDimFile.java new file mode 100644 index 0000000..546fac7 --- /dev/null +++ b/Java/storage/SimpleDimFile.java @@ -0,0 +1,137 @@ +/* +SimpleDimFile.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A simple dimension file format. + * The format consists of records: c(cell)(cell), d+(cell), d-(cell), + * Later to be extended with h(cell) which defines the + * given cell to be the headcell of its rank. + *

    + * The record types are defined by the ASCII values of the above characters. + *

    + */ + +public class SimpleDimFile implements ZZDimStorer, GZZ0.Runner{ +public static final String rcsid = "$Id: SimpleDimFile.java,v 1.6 2000/09/19 10:32:00 ajk Exp $"; + + final byte rConn = 99; + final byte rDisc = 100; + final byte rPlus = 43; + final byte rMinus = 45; + + + + ZZDimStorer sto; + public void startRead(ZZDimStorer sto) { + this.sto = sto; + } + public void endRead() { + sto = null; + } + + public int getContentType() { + return 42; + } + public int getContentVersion() { + return 0; + } + + public void readRun(InputStream is) { + DataInputStream dis = new DataInputStream(is); + boolean eofOk = true; + try { + while(true) { + eofOk = true; + byte rectype = dis.readByte(); + eofOk = false; + switch(rectype) { + case rConn: + String id1 = dis.readUTF(); + String id2 = dis.readUTF(); + sto.storeConnect(id1, id2); + break; + case rDisc: + byte bdir = dis.readByte(); + int dir; + if(bdir == rPlus) + dir = 1; + else if(bdir == rMinus) + dir = -1; + else + throw new ZZFatalError("Invalid directon"); + String id = dis.readUTF(); + sto.storeDisconnect(id, dir); + break; + default: + throw new ZZFatalError("Invalid record"); + } + } + } catch(EOFException e) { + if(!eofOk) + throw new ZZFatalError("Unexpected eof in simpledimfile"); + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + } + + DataOutputStream dos; + + public void storeConnect(String a, String b) { + try { + dos.writeByte(rConn); + dos.writeUTF(a); + dos.writeUTF(b); + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Writing file"); + } + } + public void storeDisconnect(String a, int dir) { + try { + dos.writeByte(rDisc); + dos.writeByte(dir > 0 ? rPlus : rMinus); + dos.writeUTF(a); + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Writing file"); + } + } + + public void startWrite(OutputStream dos) { + this.dos = new DataOutputStream(dos); + } + + public void endWrite() { + try { + dos.flush(); + dos = null; + } catch(IOException e) { + ZZLogger.exc(e); + throw new ZZFatalError("Reading file"); + } + } + +} diff --git a/Java/storage/Sliced.java b/Java/storage/Sliced.java new file mode 100644 index 0000000..9c9b953 --- /dev/null +++ b/Java/storage/Sliced.java @@ -0,0 +1,87 @@ +/* +Sliced.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +class FEIHFSEHFSHFSMEKFMESKUFMSEF { } + +/** EXPERIMENTAL, NOT FUNCTIONAL: A dimension created by splicing + * together several other + * dimensions. Inter-dimension connections are stored locally and + * in preflets. + *

    + * This class extends ZZLocalDimension, which is used for caching + * accesses. + *

    + * What makes things easier here is that the slice definition guarantees + * that all ranks that do not come from s.0 remain untouched. All alterations + * are insertions of ranks from the other slices + * in the middle of ranks from s.0 (of course, removing preflets and the like) + */ + +/* +public class Sliced extends ZZDimension { +public static final String rcsid = "$Id: Sliced.java,v 1.8 2000/11/07 23:07:34 tjl Exp $"; + + ZZDimension[] slices; + + ZZSlicedDimSpace sds; + + Sliced(ZZSlicedDimSpace ss, ZZDimension[] s) { + sds = ss; + slices = s; + } + + public String s(String c, int steps, ZZObs o) { + String oid = sds.getOrigID(c); + int sli = sds.getSliceID(c); + ZZDimension slice = slices[sli]; + String ores = slice.s(oid, steps, o); + if(ores==null) return null; + return sds.getConvID(sli, ores); + } + public String h(String c, int dir, ZZObs o) { + String oid = sds.getOrigID(c); + int sli = sds.getSliceID(c); + ZZDimension slice = slices[sli]; + String ores = slice.h(oid, dir, o); + if(ores==null) return null; + return sds.getConvID(sli, ores); + } + public void connect(String c, String d) { + int ci = sds.getSliceID(c); + int di = sds.getSliceID(d); + // Silently fail + if(sds.getSliceID(c) != sds.getSliceID(d)) + return; + String cor = sds.getOrigID(c); + String dor = sds.getOrigID(d); + slices[ci].connect(cor, dor); + } + public void disconnect(String c, int dir) { + String oid = sds.getOrigID(c); + int sli = sds.getSliceID(c); + slices[sli].disconnect(oid, dir); + } +} +*/ diff --git a/Java/storage/SlicedCursor.java b/Java/storage/SlicedCursor.java new file mode 100644 index 0000000..8d055ec --- /dev/null +++ b/Java/storage/SlicedCursor.java @@ -0,0 +1,149 @@ + +/* +SlicedCursor.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import org.gzigzag.*; +import java.util.*; + +/** A dimension for the sliced space cursor. + */ + +class KUHELFMSKUFHSUKFMSEF { } + +/* +public class SlicedCursor extends Sliced { +public static final String rcsid = "$Id: SlicedCursor.java,v 1.7 2000/11/07 23:07:34 tjl Exp $"; + + static boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + + String prefletdim; + + // Need several mappings: + // Our cells to preflet cells in s0. + Hashtable our2prefs = new Hashtable(); + // Preflet cells to our cells. + Hashtable pref2ours = new Hashtable(); + + SlicedCursor(ZZSlicedDimSpace ss, ZZDimension[] s, + String prefletdim) { + super(ss, s); + this.prefletdim = prefletdim; + ZZCell pr = sds.slices[0].getHomeCell(); + while((pr = pr.s(prefletdim, 1)) != null) { + loadPref(pr); + } + } + + // This cell is from the subspace. + void loadPref(ZZCell c) { + String t = c.getText(); + String i = sds.getConvID(0, c.getID()); + our2prefs.put(t, i); + pref2ours.put(i, t); + } + + public String s(String c, int steps, ZZObs o) { + // Do one by one + // VERY unoptimized. + String orig = c; + if(o != null) triggers.addObs(orig, o); + int origsteps = steps; + if(steps > 0) { + while(--steps >= 0) { + String n = getOneStepPos(c, o); + if(n==null) return null; + if(o != null) triggers.addObs(n, o); + c=n; + } + } else { + while(++steps <= 0) { + String n = getOneStepNeg(c, o); + if(n==null) return null; + if(o != null) triggers.addObs(n, o); + c=n; + } + } + p("Cursor getsteps: "+orig+" "+steps+" "+c); + return c; + } + + String getOneStepNeg(String c, ZZObs o) { + // First, if there is a real connection + String s = super.s(c, -1, o); + if(s == null) return null; + + // Then, this might be a preflet. + // Then, if it's in either hashtable + String p = (String)pref2ours.get(s); + if(p != null) + return p; + return s; + } + + String getOneStepPos(String c, ZZObs o) { + String s = (String)our2prefs.get(c); + if(s != null) { + s = super.s(s, 1, o); + // But if there's nothing, don't. + if(s != null) return s; + } + // It was not *that* special case. Now, + s = super.s(c, 1, o); + return s; + } + + public void insert(String c, int dir, String d) { + throw new ZZError("No direct insert along d.cursor allowed!"); + } + + public void connect(String c, String d) { + int ci = sds.getSliceID(c); + int di = sds.getSliceID(d); + if(ci == di) { + slices[ci].connect(sds.getOrigID(c), sds.getOrigID(d)); + return; + } + if(di != 0) + throw new ZZError("SlicedStpr: can't use non-slice0 cursors"); + String pref = (String)our2prefs.get(c); + if(pref == null) { + // No preflet, have to create our own. + ZZCell pr = sds.slices[0].getHomeCell().N(prefletdim, 1); + pr.setText(c); + loadPref(pr); + pref = pr.getID(); + } + slices[0].connect(sds.getOrigID(pref), sds.getOrigID(d)); + triggers.chg(c); + triggers.chg(d); + } + public void disconnect(String c, int dir) { + if(dir < 0) { + slices[0].disconnect(sds.getOrigID(c), -1); + } else { + throw new ZZError("Can't disconnect poswards in slicedcursor"); + } + } +} +*/ diff --git a/Java/storage/SlicedHomes.java b/Java/storage/SlicedHomes.java new file mode 100644 index 0000000..eb3fb33 --- /dev/null +++ b/Java/storage/SlicedHomes.java @@ -0,0 +1,59 @@ +/* +SlicedHomes.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import org.gzigzag.*; +import java.util.*; + +/** A simple class to connect the sliced home cells together. + * There must be a way to move between the spaces, right? + */ + +class EKUEHFKUEHFMEUFHMSEFS { } + +/* +public class SlicedHomes extends ZZRODimension { +public static final String rcsid = "$Id: SlicedHomes.java,v 1.7 2000/11/07 23:07:34 tjl Exp $"; + ZZSlicedDimSpace ss; + + Hashtable homeinds = new Hashtable(); + + SlicedHomes(ZZSlicedDimSpace ss) { + this.ss = ss; + for(int i=0; i= ss.slices.length) + return null; + return ss.getConvID(i, ss.slices[i].getHomeCellID()); + } + +} +*/ diff --git a/Java/storage/SlicedSame.java b/Java/storage/SlicedSame.java new file mode 100644 index 0000000..962d446 --- /dev/null +++ b/Java/storage/SlicedSame.java @@ -0,0 +1,50 @@ +/* +SlicedSame.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import org.gzigzag.*; +import java.util.*; + +/** A simple dimension to connect cells with the same ID in sliced + * spaces together. + */ + +class ELIJSEFIEHSFSHFSEF { } + +/* +public class SlicedSame extends ZZRODimension { + ZZSlicedDimSpace ss; + SlicedSame(ZZSlicedDimSpace ss) { + this.ss = ss; + } + + public String s(String c, int steps, ZZObs o) { + int si = ss.getSliceID(c); + String s = ss.getOrigID(c); + si += steps; + if(si < 1 || si >= ss.slices.length) + return null; + if(ss.slices[si].getCellByID(s) == null) return null; + return ss.getConvID(si, s); + } +} +*/ diff --git a/Java/storage/StreamSet.java b/Java/storage/StreamSet.java new file mode 100644 index 0000000..0a504e4 --- /dev/null +++ b/Java/storage/StreamSet.java @@ -0,0 +1,63 @@ +/* +StreamSet.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.io.*; + +/** A multi-file or multi-stream. + * Used for reading and writing multiple, named streams. + * They may be stored as a directory or as a single file, interleaved. + * Make sure you call close() after done with a stream. + */ + +public abstract class StreamSet { +String rcsid = "$Id: StreamSet.java,v 1.5 2000/09/18 14:28:22 tjl Exp $"; + + /** Obtain the inputstream associated with the given id. + * @return The input stream, or null if it doesn't exist. + */ + public abstract InputStream getInputStream(String id); + + /** Obtain an OutputStream for appending to the given id's stream. + */ + public abstract OutputStream getAppendStream(String id); + + /** Whether a stream exists. + */ + public abstract boolean exists(String id); + + /** Obtain a writable for a given id. + * This is so that string scrolls can work for now - they should + * be changed to use the usual routines. + */ + public abstract Writable getWritable(String id); + + /** Obtain a streamset for the given file. + * NOT IMPLEMENTED. Should return either directory or single-file + * stream set. + */ + static public StreamSet get(File f) { + return null; + } +} + + diff --git a/Java/storage/Writable.java b/Java/storage/Writable.java new file mode 100644 index 0000000..b5c7360 --- /dev/null +++ b/Java/storage/Writable.java @@ -0,0 +1,37 @@ +/* +Writable.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A part of a multi-file or other nearly append-only storage. + */ + +public interface Writable { +String rcsid = "$Id: Writable.java,v 1.5 2000/09/19 10:32:01 ajk Exp $"; + void write(long offset, byte[] data); + byte[] read(long offset, int n); + void read(long offset, byte b[], int off, int len); + long length(); + void flush(); +} + diff --git a/Java/storage/ZZCacheContentStore.java b/Java/storage/ZZCacheContentStore.java new file mode 100644 index 0000000..8326cc0 --- /dev/null +++ b/Java/storage/ZZCacheContentStore.java @@ -0,0 +1,122 @@ +/* +ZZCacheContentStore.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A locally cached content storage, which tracks text changes. + */ +public class ZZCacheContentStore implements ContentStore, + ContentStorer { +public static final String rcsid = "$Id: ZZCacheContentStore.java,v 1.7 2000/09/19 10:32:01 ajk Exp $"; + public static boolean dbg = false; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + UndoList undo; + public void setUndoList(UndoList l) { undo = l; } + + ZZCacheDimSpace ds; + public void setSpace(ZZCacheDimSpace s) { ds = s; } + + /** The current contents. */ + Hashtable c = new Hashtable(); + + /** The earlier connection on each cell's poswards or negwards + * direction at commit time. + * This list is created at commit time by reversing all operations + * so we can then compare these values and the current values to + * see which have changed. + * Hmm.. do we really even need comm? + */ + Hashtable com; + + static final Object nolla = new Object(); + + synchronized public void startCommit() { + com = new Hashtable(); + } + + synchronized public void endCommit(ContentStorer sto) { + for(Enumeration e = com.keys(); + e.hasMoreElements();) { + String id = (String)e.nextElement(); + Object chgfrom = com.get(id); + Object chgto = c.get(id); + if(chgfrom == nolla) chgfrom = null; + if(chgfrom == chgto || + (chgfrom != null && chgfrom.equals(chgto))) + continue; + sto.putContent(id, chgto); + } + com = null; + } + + /** The abstracted operation of connecting two cells. + * Parameters: cell1 cell2. + * The cells are explicitly assumed to be not connected before + * this. + */ + protected class ChangeContent implements UndoList.Op { + public void undo(Object[] list, int nth) { + String id = (String)list[nth+1]; + Object before = list[nth+2]; + Object after = list[nth+3]; + if(before == null) + c.remove(id); + else + c.put(id, before); + ds.invalidateText(id); + } + public void redo(Object[] list, int nth) { + String id = (String)list[nth+1]; + Object before = list[nth+2]; + Object after = list[nth+3]; + c.put(id, after); + ds.invalidateText(id); + } + public void commit(Object[] list, int nth) { + String id = (String)list[nth+1]; + Object before = list[nth+2]; + Object after = list[nth+3]; + if(before == null) + com.put(id, nolla); + else + com.put(id,before); + } + } + + protected ChangeContent mychange = new ChangeContent(); + + public Object get(String id) { + return c.get(id); + } + public void put(String id, Object o) { + undo.add(mychange, id, c.get(id), o); + p("SetText: "+id+" '"+o+"'"); + c.put(id, o); + } + public void putContent(String id, Object o) { + c.put(id, o); + } + +} diff --git a/Java/storage/ZZCacheDimSpace.java b/Java/storage/ZZCacheDimSpace.java new file mode 100644 index 0000000..41f870d --- /dev/null +++ b/Java/storage/ZZCacheDimSpace.java @@ -0,0 +1,249 @@ +/* +ZZCacheDimSpace.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; +import java.lang.reflect.*; + +/** A dimspace that uses a StreamSet to be persistent. + * XXX Triggers to undo events?!?!? Existing ZZCells deleted?? + */ + +public class ZZCacheDimSpace extends ZZDimSpace { +public static final String rcsid = "$Id: ZZCacheDimSpace.java,v 1.28 2001/03/08 13:54:20 ajk Exp $"; + + protected int maxtimestamp; + + StreamSet strs; + + // XXX Stamps! + UndoList ul = new UndoList(2935); + ZZCacheContentStore ct = new ZZCacheContentStore(); + + Hashtable scrolls = new Hashtable(); + int timestamp = 1; + + synchronized public int stamp() { return ul.stamp(); } + synchronized public void undo() { ul.undo(); } + synchronized public void redo() { ul.redo(); } + synchronized public int commit() { + if (readonly) return timestamp; + p("COMMIT!"); + // Put in time of last save. Not used anywhere yet. + ct.put("savetime", ""+System.currentTimeMillis()); + for(Enumeration e = dims.keys(); + e.hasMoreElements(); ) { + String dname = (String)e.nextElement(); + ZZDimension d = (ZZDimension)dims.get(dname); + if(d instanceof ZZCacheDimension) { + ZZCacheDimension cd = (ZZCacheDimension)d; + cd.startCommit(); + } + } + ct.startCommit(); + ul.commit(); + int stmp = ++timestamp; + SimpleDimFile outf = new SimpleDimFile(); + for(Enumeration e = dims.keys(); + e.hasMoreElements(); ) { + String dname = (String)e.nextElement(); + ZZDimension d = (ZZDimension)dims.get(dname); + if(d instanceof ZZCacheDimension) { + ZZCacheDimension cd = (ZZCacheDimension)d; + + GZZ0 writ = new GZZ0(strs, dname); + + writ.startWrite(stmp, outf); + cd.endCommit(outf); + writ.endWrite(false); + } + } + SimpleContentFile coutf = new SimpleContentFile(); + GZZ0 cwrit = new GZZ0(strs, "CONTENT"); + cwrit.startWrite(stmp, coutf); + ct.endCommit(coutf); + cwrit.endWrite(true); + for (Enumeration e = spaceParts.keys(); e.hasMoreElements();) { + String s = (String)e.nextElement(); + ZZSpacePart sp = (ZZSpacePart)spaceParts.get(s); + sp.postCommitHook(); + } + return stmp; + } + + public ZZCacheDimSpace(StreamSet w) { + this(w, -1); + } + + public ZZCacheDimSpace(ZZCacheDimSpace cds, int tstamp) { + this(cds.strs, tstamp); + } + + public ZZCacheDimSpace(StreamSet w, int tstamp) { + this(w, tstamp, (tstamp != -1)); + } + + public ZZCacheDimSpace(StreamSet w, int tstamp, boolean readonly) { + super(readonly); + + strs = w; + + ct.setUndoList(ul); + ct.setSpace(this); + + maxtimestamp = tstamp; + + if(strs.exists("CONTENT")) { + SimpleContentFile cinf = new SimpleContentFile(); + GZZ0 crea = new GZZ0(strs, "CONTENT"); + cinf.startRead(ct); + timestamp = crea.read(cinf, tstamp); + cinf.endRead(); + } else { + // The id of the next free cell must be stored in the space, + // this is a kludge. + ct.put("nextfreeid", nextID); + // The home cell is called HOME + ct.put("1", "HOME"); + } + nextID = (String)ct.get("nextfreeid"); + + spaceParts.put("bintree", new BinaryTreePart(this, "bintree")); + spaceParts.put("imptree", new ImpliedTreePart(this, "imptree")); + spaceParts.put("imptree2", new ImpliedTreePart2(this, "imptree2")); + spaceParts.put("doubler", new DoubleStepPart(this, "doubler")); + spaceParts.put("version", new VersionPart(this, "version")); + + spaceParts.put("gentreetest", new GenTreePart(this, "gentreetest", + new GenTreeTestModel())); + + try { + spaceParts.put("nile1str", new GenTreePart(this, "nile1str", + (GenTreePartModel) + Class.forName("org.gzigzag.module.Nile1GenTreeModel"). + newInstance())); + } catch(Exception e) { + p("Nile module not found - this is not fatal unless you know what nile is. Don't worry."); + } + + try { + Class ztp = Class.forName("org.zaubertrank.ZaubertrankPart"); + Class zzsp = Class.forName("org.gzigzag.ZZSpace"); + Constructor ztpc = ztp.getConstructor(new Class[] { + zzsp, "".getClass() }); + ZZSpacePart sp = (ZZSpacePart) + ztpc.newInstance(new Object[] { this, "zaubertrank" }); + spaceParts.put("zaubertrank", sp); + } catch (ClassNotFoundException e) { + // ignore: that Zaubertrank stack trace is annoying + } catch(Throwable t) { + ZZLogger.exc(t); + // the zaubertrank isn't compiled by standard, so don't tell + } + + } + + protected void setNextID(String s) { + super.setNextID(s); + ct.put("nextfreeid", nextID); + } + + protected Span getSpan(String id) { + Object o = ct.get(id); + if(!(o instanceof Span)) + return null; + return (Span)o; + } + protected String getText(String id) { + Object o = ct.get(id); + if(o==null) return ""; + if(o instanceof Span) + o = ((Span)o).getString(getHomeCell()); + return (String)o; + } + + protected void setText(String id, Object cont) { + if (readonly) throw new ZZError("readonly space"); + ct.put(id, cont); + } + + + + protected ZZDimension createDimension(String s) { + if(!validDim(s)) return null; + if(s.indexOf(':') != -1) return createPartDimension(s); + + + ZZDimension d; + if(s.equals("d.cellcreation")) { + d = new IDDimension(); + } else { + ZZCacheDimension dim = new ZZCacheDimension(readonly); + dim.setUndoList(ul); + InputStream is = strs.getInputStream(s); + if(strs.exists(s)) { + SimpleDimFile inf = new SimpleDimFile(); + inf.startRead(dim); + GZZ0 rea = new GZZ0(strs, s); + rea.read(inf, maxtimestamp); + inf.endRead(); + } + d = dim; + } + d.setSpace(this); + return d; + } + + + public String getIDOrNull() { + Object o = ct.get("spaceid"); + if (!(o instanceof String)) { + return null; + } + return (String)o; + } + + + + public void setID(String id) { + if (readonly) throw new ZZError("readonly space"); + ct.put("spaceid", id); + } + + public StringScroll getStringScroll() { + return getStringScroll("text"); + } + public StringScroll getStringScroll(String name) { + StringScroll scr; + if((scr = (StringScroll)scrolls.get(name)) == null) { + Writable wr = strs.getWritable("STRSCR_"+name); + scr = new StringScroll(name, wr, readonly); + // XXX ??? + Scroll.register(name, scr); + scrolls.put(name, scr); + } + return scr; + } + + +} diff --git a/Java/storage/ZZCacheDimension.java b/Java/storage/ZZCacheDimension.java new file mode 100644 index 0000000..97cfae5 --- /dev/null +++ b/Java/storage/ZZCacheDimension.java @@ -0,0 +1,281 @@ +/* +ZZCacheDimension.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** Dimension-centric implementation of a locally + * cached dimension. + * This class may be used as a cache to + * a dimension stored on disk, and includes facilities for tracking + * the changes. + * XXX Look into replacing hashtable with a more memory-saving constructions? + *

    + * This, uglily, shares some code with ZZLocalDimension but making + * this an inheritance relationship would have been difficult, and + * the point is to keep ZZLocalDimension a truly simple basic + * example implementation of a dimension. + *

    + * The mechanism for the undolist is quite interesting: + * we save each connect / disconnect operation with the two cells, + * so we know the inverse of each operation. + * We can then, at commit time, build a hash table by taking the first + * operation and seeing if it cancels an earlier operation (undolist does + * commits in reverse order) and if it does, we do nothing. + * This allows the user to move the cursor without wasting storage on all + * positions. + * Interestingly, although we store all connections bidirectionally as + * connect/disconnect pairs in the undolist, we cannot save them like that + * after compression: they must be saved as single-sided disconnects and + * pair connects. + */ +public class ZZCacheDimension extends ZZDimension implements ZZDimStorer { +public static final String rcsid = "$Id: ZZCacheDimension.java,v 1.11 2001/02/23 08:33:37 ajk Exp $"; + public static final boolean dbg = true; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + UndoList undo; + public void setUndoList(UndoList l) { undo = l; } + + protected boolean readonly; + + public ZZCacheDimension() { this(false); } + public ZZCacheDimension(boolean readonly) { + this.readonly = readonly; + } + + /** Connections to the positive direction. */ + Hashtable cp = new Hashtable(); + /** Connections to the negative direction. */ + Hashtable cm = new Hashtable(); + + /** The earlier connection on each cell's poswards or negwards + * direction at commit time. + * This list is created at commit time by reversing all operations + * so we can then compare these values and the current values to + * see which have changed. + * Hmm.. do we really even need comm? + */ + Hashtable comp; + Hashtable comm; + + /** A null marker for the hashtables. */ + static final Object nolla = new Object(); + + synchronized public void startCommit() { + if (readonly) throw new ZZError("readonly dimension"); + comp = new Hashtable(); + comm = new Hashtable(); + } + + synchronized public void endCommit(ZZDimStorer sto) { + if (readonly) throw new ZZError("readonly dimension"); + for(Enumeration e = comp.keys(); + e.hasMoreElements();) { + String id = (String)e.nextElement(); + Object oidto = comp.get(id); + String idto = (oidto == nolla ? null : (String)oidto); + String idwasto = (String)cp.get(id); + // If it's the same, then nevermind. + if(idto == idwasto || ( + idto != null && idto.equals(idwasto))) + continue; + if(idwasto != null) + sto.storeConnect(id, idwasto); + else + sto.storeDisconnect(id, 1); + + } + for(Enumeration e = comm.keys(); + e.hasMoreElements();) { + String id = (String)e.nextElement(); + Object oidto = comm.get(id); + String idto = (oidto == nolla ? null : (String)oidto); + String idwasto = (String)cm.get(id); + // If it's the same, then nevermind. + if(idto == idwasto || ( + idto != null && idto.equals(idwasto))) + continue; + if(idwasto == null) + sto.storeDisconnect(id, -1); + // Not here: we only call connect once. + // else + // sto.connect(id, -1, idto); + + } + comp = null; + comm = null; + } + + ZZCellHandle ch(Object o) { + if(o instanceof ZZCellHandle) return (ZZCellHandle)o; + return (ZZCellHandle)space.getCellByID((String)o); + } + String cid(Object o) { + if(o instanceof ZZCellHandle) return ((ZZCellHandle)o).id; + return (String)o; + } + + /** The abstracted operation of connecting two cells. + * Parameters: cell1 cell2. + * The cells are explicitly assumed to be not connected before + * this. + */ + protected class Connect implements UndoList.Op { + public void undo(Object[] list, int nth) { + String c1 = (String)list[nth+1]; + String c2 = (String)list[nth+2]; + if(!s((ZZCellHandle)space.getCellByID(c1), 1, null).id.equals(c2)) + throw new ZZError( + "Error when undoing change: disconnect assertion broken"); + cp.remove(c1); + cm.remove(c2); + triggers.chg(c1); + triggers.chg(c2); + } + public void redo(Object[] list, int nth) { + String c1 = (String)list[nth+1]; + String c2 = (String)list[nth+2]; + if(cp.get(c1) != null || + cm.get(c2) != null) + throw new ZZError( + "Error when redoing change: unconnected assertion broken"); + cp.put(c1, c2); + cm.put(c2, c1); + triggers.chg(c1); + triggers.chg(c2); + } + public void commit(Object[] list, int nth) { + String c1 = (String)list[nth+1]; + String c2 = (String)list[nth+2]; + comp.put(c1, nolla); + comm.put(c2, nolla); + } + } + + + /** The abstracted operation of disconnecting two cells. + * Parameters: cell1 cell2. + */ + protected class Disconnect implements UndoList.Op { + public void undo(Object[] list, int nth) { + String c1 = (String)list[nth+1]; + String c2 = (String)list[nth+2]; + // Note we can't use disconnect() since that would make + // new undolist entries. + if(cp.get(c1) != null || + cm.get(c2) != null) + throw new ZZError( + "Error when undoing change: unconnected assertion broken"); + cp.put(c1, c2); + cm.put(c2, c1); + triggers.chg(c1); + triggers.chg(c2); + } + public void redo(Object[] list, int nth) { + String c1 = (String)list[nth+1]; + String c2 = (String)list[nth+2]; + if(!s((ZZCellHandle)space.getCellByID(c1), 1, null).id.equals(c2)) + throw new ZZError( + "Error when redoing change: disconnect assertion broken"); + cp.remove(c1); + cm.remove(c2); + triggers.chg(c1); + triggers.chg(c2); + } + public void commit(Object[] list, int nth) { + String c1 = (String)list[nth+1]; + String c2 = (String)list[nth+2]; + comp.put(c1, c2); + comm.put(c2, c1); + } + } + + Connect myconnect = new Connect(); + Disconnect mydisconnect = new Disconnect(); + + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + String s = c.id; + if(o != null) triggers.addObs(s, o); + if(steps>0) + while(steps-- > 0 && s != null) { + s = (String)cp.get(s); + if(o != null && s!=null) triggers.addObs(s, o); + } + else + while(steps++ < 0 && s != null) { + s = (String)cm.get(s); + if(o != null && s!=null) triggers.addObs(s, o); + } + if(s==null) return null; + return (ZZCellHandle)space.getCellByID(s); + } + + public void connect(ZZCellHandle c0, ZZCellHandle d0) { + if (readonly) throw new ZZError("readonly dimension"); + String c = c0.id; + String d = d0.id; + disconnect(c0, 1); + disconnect(d0, -1); + cp.put(c, d); + cm.put(d, c); + undo.add(myconnect, c, d); + triggers.chg(c); + triggers.chg(d); + } + + public void disconnect(ZZCellHandle c0, int dir) { + if (readonly) throw new ZZError("readonly dimension"); + String c = c0.id; + String o; + if(dir>0) { + o = (String)cp.get(c); + if(o!=null) { + undo.add(mydisconnect, c, o); + cp.remove(c); + cm.remove(o); + } + } else { + o = (String)cm.get(c); + if(o!=null) { + undo.add(mydisconnect, o, c); + cm.remove(c); + cp.remove(o); + } + } + triggers.chg(c); + if(o!=null) triggers.chg(o); + } + + // ZZDimStorer implementation + + public void storeConnect(String a, String b) { + cp.put(a, b); + cm.put(b, a); + } + public void storeDisconnect(String a, int dir) { + Hashtable h = (dir > 0 ? cp : cm); + h.remove(a); + } + +} diff --git a/Java/storage/ZZDimStorer.java b/Java/storage/ZZDimStorer.java new file mode 100644 index 0000000..27e294a --- /dev/null +++ b/Java/storage/ZZDimStorer.java @@ -0,0 +1,47 @@ +/* +ZZDimStorer.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** A simple interface between persistent and temporary storage. + * This class is used simply for transmitting information about + * connections. + *

    + * The speciality of this class is that the operations need not make + * sense atomically: only the end result of several operations counts. + * So if a is connected to b, then connect(b, -, c), disconnect(a, +), + * is perfectly valid. + * All disconnections must be given in both directions; connects + * only once (that's why there's no dir there). + *

    + * If the above seems unclear, just see how it's used and where + * it's not used: the class that is used for the on-line dims is ZZDimension. + */ + +public interface ZZDimStorer { +String rcsid = "$Id: ZZDimStorer.java,v 1.4 2000/09/19 10:32:01 ajk Exp $"; + void storeConnect(String a, String b); + void storeDisconnect(String a, int dir); +} diff --git a/Java/transform/ChangeDim.java b/Java/transform/ChangeDim.java new file mode 100644 index 0000000..21334d5 --- /dev/null +++ b/Java/transform/ChangeDim.java @@ -0,0 +1,58 @@ +/* +ChangeDim.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace dimension changer - substitute a dimension name with another + */ + +public class ChangeDim { +String rcsid = "$Id: ChangeDim.java,v 1.5 2000/10/18 14:35:32 tjl Exp $"; + String olddim, newdim; + ZZSpace space; +/** Constructs dimension changer for a space + * @param od The old dimension + * @param nd The new dimension + * @param s The space to convert + */ + public ChangeDim(String od, String nd, ZZSpace s) { + olddim = od; + newdim = nd; + space = s; + } + +/** Performs the actual transformation. All connections along the old + * dimension are disconnected and new ones connected along the new dimension. + */ + public void transform() { + Enumeration e=space.cells(); + ZZCell c, n; + while(e.hasMoreElements()) { + c = (ZZCell)e.nextElement(); + n = c.s(olddim, 1); + if(n!=null) { + c.disconnect(olddim, 1); + c.connect(newdim, 1, n); + } + } + } +} diff --git a/Java/transform/ClearDim.java b/Java/transform/ClearDim.java new file mode 100644 index 0000000..c5a5fc2 --- /dev/null +++ b/Java/transform/ClearDim.java @@ -0,0 +1,55 @@ +/* +ClearDim.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace dimension clearer - disconnects every connection along a dimension + */ + +public class ClearDim { +String rcsid = "$Id: ClearDim.java,v 1.4 2000/10/18 14:35:32 tjl Exp $"; + String dim; + ZZSpace space; +/** Constructs dimension changer for a space + * @param od The old dimension + * @param nd The new dimension + * @param s The space to convert + */ + public ClearDim(String d, ZZSpace s) { + dim = d; + space = s; + } + +/** Performs the actual transformation. All connections along the + * dimension are simply disconnected. + */ + public void transform() { + Enumeration e=space.cells(); + ZZCell c, n; + while(e.hasMoreElements()) { + c = (ZZCell)e.nextElement(); + if(c.s(dim, 1)!=null) { + c.disconnect(dim, 1); + } + } + } +} diff --git a/Java/transform/CopyDim.java b/Java/transform/CopyDim.java new file mode 100644 index 0000000..51f2e52 --- /dev/null +++ b/Java/transform/CopyDim.java @@ -0,0 +1,58 @@ +/* +CopyDim.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace dimension copier - duplicate connections of a dimension into + * another dimension + */ + +public class CopyDim { +String rcsid = "$Id: CopyDim.java,v 1.4 2000/10/18 14:35:32 tjl Exp $"; + String olddim, newdim; + ZZSpace space; +/** Constructs dimension changer for a space + * @param od The old dimension + * @param nd The new dimension + * @param s The space to convert + */ + public CopyDim(String od, String nd, ZZSpace s) { + olddim = od; + newdim = nd; + space = s; + } + +/** Performs the actual transformation. All connections along the old + * dimension are recreated along the new dimensions. + */ + public void transform() { + Enumeration e=space.cells(); + ZZCell c, n; + while(e.hasMoreElements()) { + c = (ZZCell)e.nextElement(); + n = c.s(olddim, 1); + if(n!=null) { + c.connect(newdim, 1, n); + } + } + } +} diff --git a/Java/transform/FoldDim.java b/Java/transform/FoldDim.java new file mode 100644 index 0000000..3b100ef --- /dev/null +++ b/Java/transform/FoldDim.java @@ -0,0 +1,76 @@ +/* +FoldDim.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + * (Borrowing heavily from ReverseDim.java by Tuukka Hastrup) + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** "Fold" a dimension into two new ones + * Take one start and two result dimensions. Target dim + */ + +public class FoldDim { +String rcsid = "$Id: FoldDim.java,v 1.4 2000/10/18 14:35:32 tjl Exp $"; + public static final boolean dbg = false; + void p(String s) { if (dbg) System.out.println(s); } + void pa(String s) { System.out.println(s); } + + String dim, hdim; // Headcell dim + ZZSpace space; + + public FoldDim(String d, String h, ZZSpace s) { + dim=d; hdim=h; space=s; + } + + public void transform() { + Enumeration e=space.cells(); + ZZCell c; + Hashtable donecells = new Hashtable(); // Cells on the folded ranks + while(e.hasMoreElements()) { // Do ranks + c = (ZZCell)e.nextElement(); + if(c.s(dim, -1)==null) { + if (c.s(dim, 1)!=null) { + if(!donecells.containsKey(c)) { + ZZCell next = c.s(dim, 1); + c.disconnect(dim, 1); c.connect(hdim, 1, next); + donecells.put(c, c); + for(; next != null; next=next.s(dim, 1)) + donecells.put(next, next); + p("Folded rank beginning from cell #"+c.getID()); + } + else + p("Rank beginning from cell #"+c.getID()+" already done"); + } + else + p("Cell #"+c.getID()+" not placed on "+dim); + donecells.put(c, c); // This cell is not in loop + } // Negwards connected cells will be done later + } + e = space.cells(); + while(e.hasMoreElements()) { // Detect loops + c = (ZZCell)e.nextElement(); + if(!donecells.containsKey(c)) { // If it wasn't rank, then it's loop + pa("FoldDim couldn't convert cell on loop, #"+c.getID()+ + ", '"+c.getText()+"'"); + } + } + } +} \ No newline at end of file diff --git a/Java/transform/ReverseDim.java b/Java/transform/ReverseDim.java new file mode 100644 index 0000000..17c7976 --- /dev/null +++ b/Java/transform/ReverseDim.java @@ -0,0 +1,96 @@ +/* +ReverseDim.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace dimension changer - reverse positive and negative directions. + */ + +public class ReverseDim { +String rcsid = "$Id: ReverseDim.java,v 1.6 2000/10/18 14:35:32 tjl Exp $"; + public static final boolean dbg = false; + void p(String s) { if (dbg) System.out.println(s); } + String dim; + ZZSpace space; +/** Constructs direction changer for a dimension in a space + * @param d The dimension + * @param s The space to convert + */ + public ReverseDim(String d, ZZSpace s) { + dim = d; + space = s; + } + +/** Performs the actual transformation. All connections along the dimension + * are disconnected and new ones connected in reverse direction. + */ + public void transform() { + Enumeration e=space.cells(); + ZZCell c; + Hashtable donecells = new Hashtable(); // Cells on the reversed ranks + while(e.hasMoreElements()) { // Do ranks + c = (ZZCell)e.nextElement(); + if(c.s(dim, -1)==null) { + if (c.s(dim, 1)!=null) { + if(!donecells.containsKey(c)) { + swapRank(c, donecells); + p("Swapped rank beginning from cell #"+c.getID()); + } + else + p("Rank beginning from cell #"+c.getID()+" already done"); + } + else + p("Cell #"+c.getID()+" not placed on "+dim); + donecells.put(c, c); // This cell is not in loop + } // Negwards connected cells will be done later + } + e = space.cells(); + while(e.hasMoreElements()) { // Do loops + c = (ZZCell)e.nextElement(); + if(!donecells.containsKey(c)) { // If it wasn't rank, then it's loop + c.disconnect(dim, -1); // Cut into a rank + c.connect(dim, 1, swapRank(c, donecells)); // Flip and join + } + } + } + + // Swap the cells in a rank. Return the new headcell. + protected ZZCell swapRank(ZZCell head, Hashtable done) + { + ZZCell newrank = head; // The latest cell in the new rank + ZZCell curr = head.s(dim, 1); // The head of the old one + head.disconnect(dim, 1); + ZZCell next; + while (curr != null) { + next = curr.s(dim, 1); + if(next!=null) { + curr.disconnect(dim, 1); + } + curr.connect(dim, 1, newrank); + done.put(curr, curr); + newrank = curr; + curr = next; + }; + return newrank; + } +} + diff --git a/Java/transform/Version0.java b/Java/transform/Version0.java new file mode 100644 index 0000000..5ab67cc --- /dev/null +++ b/Java/transform/Version0.java @@ -0,0 +1,66 @@ +/* +Version0.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace version changer - from version 0 to version 1. + */ + +public class Version0 implements VersionChanger { +String rcsid = "$Id: Version0.java,v 1.7 2000/10/18 14:35:32 tjl Exp $"; + static public final void pa(String s) { System.out.println(s); } + static public final void pan(String s) { System.out.print(s); } +/** Change the space from version 0 to version 1 to make it compatible: + *

      + *
    • d.mycursor is renamed to d.cursor-cargo + *
    • d.cursor-cargo and d.cursor directions are reversed + *
    • System cell "FlobCanvasRasters" is renamed as "FlobRasters" + *
    + * Note that flobs will not work before a new client space is created + * with command line options new and dcold. + * @param s The space to convert + */ + public int changeVersion(ZZSpace s) { + pa("Converting from version 0 to version 1:"); + pa("Cursor dimensions rearranged for consistency."); + pan("Changing d.mycursor connections to d.cursor-cargo:"); + (new ChangeDim("d.mycursor", "d.cursor-cargo", s)).transform(); + pa(" Name changed."); + pan("Reversing connections along d.cursor and d.cursor-cargo:"); + (new ReverseDim("d.cursor", s)).transform(); + (new ReverseDim("d.cursor-cargo", s)).transform(); + pa(" Headcell (negend) now accursed."); + pa("The new flob code won't work unless you create " + + "new client space (options -new and -dcold)."); + pa("Changing the system cell \"FlobCanvasRasters\" " + + "to \"Flobrasters\" to respect code changes."); + ZZCell frasters = s.getHomeCell() + .findText("d.2", 1, "FlobCanvasRasters"); + if(frasters != null) { + frasters.setText("FlobRasters"); + frasters.disconnect("d.1", 1); + frasters.N("d.1", 1).setText("dummy"); + } + return 1; + } +} + diff --git a/Java/transform/Version1.java b/Java/transform/Version1.java new file mode 100644 index 0000000..ad470ec --- /dev/null +++ b/Java/transform/Version1.java @@ -0,0 +1,56 @@ +/* +Version0.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace version changer - from version 1 to version 2. + */ + +public class Version1 implements VersionChanger { +String rcsid = "$Id: Version1.java,v 1.3 2000/09/19 10:32:01 ajk Exp $"; + static public final void pa(String s) { System.out.println(s); } + static public final void pan(String s) { System.out.print(s); } +/** Change the space from version 1 to version 2 to make it compatible. + * Change to 3-dimension cursing system, allowing every cell to be accursed: + *
      + *
    1. fold d.cursor's headcells onto TMPDIM + *
    2. change d.cursor to d.cursor-list + *
    3. change TMPDIM to d.cursor + *
    + * @param s The space to convert + */ + public int changeVersion(ZZSpace s) { + pa("Converting from version 1 to version 2:"); + pa("Change to 3-dimension cursing system."); + pan("Folding d.cursor's headcells to TMPDIM... "); + (new FoldDim("d.cursor", "TMPDIM", s)).transform(); + pa("done."); + pan("Renaming to d.cursor and d.cursor-list... "); + (new ChangeDim("d.cursor", "d.cursor-list", s)).transform(); + pan("d.cursor-list done... "); + (new ChangeDim("TMPDIM", "d.cursor", s)).transform(); + pa(" d.cursor done."); + pa("Converted to version 2."); + return 2; + } +} + diff --git a/Java/transform/Version2.java b/Java/transform/Version2.java new file mode 100644 index 0000000..d3f6eda --- /dev/null +++ b/Java/transform/Version2.java @@ -0,0 +1,44 @@ +/* +Version2.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** ZZspace version changer - from version 2 to version 3. + * The change in the structure is that now rasters have names, + * and rasters are called views. + */ + +public class Version2 implements VersionChanger { +String rcsid = "$Id: Version2.java,v 1.3 2000/09/19 10:32:01 ajk Exp $"; + static public final void pa(String s) { System.out.println(s); } + static public final void pan(String s) { System.out.print(s); } +/** Change the space from version 2 to version 3 to make it compatible. + * Simply recreates the system part of the space, since we now use names for views. + */ + public int changeVersion(ZZSpace s) { + pa("Converting from version 2 to version 3:"); + pa("Recreating system space (not disconnecting old)"); + ZZDefaultSpace.create(s.getHomeCell(), false); + return 3; + } +} + diff --git a/Java/transform/VersionChanger.java b/Java/transform/VersionChanger.java new file mode 100644 index 0000000..488317c --- /dev/null +++ b/Java/transform/VersionChanger.java @@ -0,0 +1,37 @@ +/* +VersionChanger.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ +package org.gzigzag.transform; +import java.util.*; +import org.gzigzag.*; + +/** A general interface for changing ZZspaces between versions. + */ +public interface VersionChanger { +String rcsid = "$Id: VersionChanger.java,v 1.4 2000/09/19 10:32:01 ajk Exp $"; + /** Takes the space which conforms to client space version of the + * converter class. Needed transformations are then carried out + * to make the space conform to a newer version returned. + * @param s The space to convert + * @return The new version of the space + */ + int changeVersion(ZZSpace s); +} + diff --git a/Java/zob2java.pl b/Java/zob2java.pl new file mode 100644 index 0000000..4f58de0 --- /dev/null +++ b/Java/zob2java.pl @@ -0,0 +1,302 @@ +# +# zob2java.pl +# * +# * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka +# * +# * You may use and distribute under the terms of either the GNU Lesser +# * General Public License, either version 2 of the license or, +# * at your choice, any later version. Alternatively, you may use and +# * distribute under the terms of the XPL. +# * +# * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# * the licenses. +# * +# * This software 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 README +# * file for more details. +# * +# */ +# /* +# * Written by Tuomas Lukka +# */ +# + +# $out = $ARGV[0]; +# $out =~ s/\.zob/\.java/ or die("Can't change filename for output file"); + +@ARGV == 2 or die "Two params: infile outfile"; + +$outfile = pop @ARGV; +$infile = $ARGV[0]; + +$init .= <; + +$str =~ s/\bFONTMETRICS\s*\((.*?)\)/(ScalableFont.fmComp.getFontMetrics($1))/g; + +# ZObs must implement ZOb themselves. +# +# $str =~ s/\b(implements\s+)/$1 ZOb, / +# or $str =~ s/(^[\w\s]*\bclass\b[\w\s]*)({)/$1 implements ZOb $2/ +# or die "Can't implement ZOb - didn't find subst place"; + +$str =~ s/INITIALIZE/protected void init__zob() / + and $doinit = "init__zob();"; + +# $structparre = 'STRUCTPARAMS;?(.*)END STRUCTPARAMS;?'; + +# $str =~ /$structparre/s; + +# $pars = $1; + +# FIXME: this parser takes into account braces in comments +sub parse_balanced { + my $str = $_[0]; + my $rv = ""; + my $level = 1; + + while ($level > 0) { + die "Unbalanced braces" if $str eq ""; + $str =~ /^([^{}]*)([{}])(.*)$/s; + my($brace1, $brace2, $rest) = ($1, $2, $3); + if ($brace2 eq "{") { ++$level; } + if ($brace2 eq "}") { --$level; } + $str = $rest; + $rv = $rv . $brace1 . $brace2; + } + return ($rv, $str); +} + +$str =~ /^(.*)STRUCTPARAMS *{(.*)$/s or die "No STRUCTPARAMS SECTION"; +$beforestructpars = $1; +($pars, $afterstructpars) = parse_balanced($2); +$pars =~ s/}$//s; + +@pars = map { /^\s*$/ ? () : $_ } split /\n\s*\n/, $pars; + +%gets = ( +"float" => '__TARG__ = (Float.valueOf(__SRC__)).floatValue();', +"double" => '__TARG__ = (Double.valueOf(__SRC__)).doubleValue();', +"int" => '__TARG__ = Integer.parseInt(__SRC__); ', +"boolean" => ' + if(__SRC__.equals("true")) __TARG__=true; + else if(__SRC__.equals("false")) __TARG__=false; + else { /* XXX ??? */ } +', +Font => ' + { + ZZCell c1 = c.s("d.1"); + int size = 12; + int style = Font.PLAIN; + if(c1 != null) { + size = Integer.parseInt(c1.getText()); + ZZCell c2 = c1.s("d.1"); + if(c2 != null) { + String sty = c2.getText(); + if(sty.equals("BOLD")) + style = Font.BOLD; + if(sty.equals("ITALIC")) + style = Font.ITALIC; + else { + // error... + } + } + } + __TARG__ = new Font(s, style, size); + } +', +ScalableFont => ' + { + ZZCell c1 = c.s("d.1"); + int size = 12; + int style = Font.PLAIN; + if(c1 != null) { + size = Integer.parseInt(c1.getText()); + ZZCell c2 = c1.s("d.1"); + if(c2 != null) { + String sty = c2.getText(); + if(sty.equals("BOLD")) + style = Font.BOLD; + if(sty.equals("ITALIC")) + style = Font.ITALIC; + else { + // error... + } + } + } + __TARG__ = new ScalableFont(s, style, size); + } +', +String => '__TARG__ = __SRC__; ', +Color => '__TARG__ = Color.decode(__SRC__); ', +ZZPath => ' + __TARG__ = ZZPath.createFromStructure1(__SRCCELL__.s("d.2")); +', +ZOb => ' + { + __TARG__ = ZZDefaultSpace.readZOb(__SRCCELL__); + // __TARG__ = ZZDefaultSpace.newZOb(__SRC__); + // __TARG__.readParams(__SRCCELL__.s("d.2")); + + } +', +ZZCell => ' + { + __TARG__ = __SRCCELL__; + } +', +); + +my $curbit = -1; + +# Remove comments +for(@pars) { + print "Par: $_"; + # Move comment + my $comment; + if(m|^(\s*/\*.*\*/)(.*)|s) { + $comment = $1; + $_ = $2; + } else { + # die "No comment for structparam '$_' in $infile"; + $comment = "/** UNDOCUMENTED. \n */"; + } + if(m|=(.*)|) { + my $def = $1; + print "DEFAULT: $def\n\n"; + $comment =~ s|\*/|\n *

    Default value:

    $def
    . \n */| + or die "Comment '$comment' not substitutable" ; + } else { + print "NO DEFAULT: $_\n\n"; + } + # Add new tag: structparam + $comment =~ s|\*/|\n * \@structparam 1 \n */ \n\n|g; + $publicpars .= $comment; + + $publicpars .= " public ".$_; + s|/\*.*?\*/||gs ; + s/^\s*//s; + s/\s*$//s; + m|^(\w+\s*(?:\[\s*\]\s*)*)\s* + (\w+)\s* + ((?://.*\n)?)\s* + |x or die "Invalid param: $_"; + # push @types, $1; + # push @names, $2; + # push @ranges, $3; + + my($type, $name, $range) = ($1, $2, $3); + + $type =~ s/\s+//g; + $type =~ /^(\w+)((?:\[\])?)$/ or die "Invalid type '$type'"; + + my $base = $1; + my $array = ($2 eq "[]"); + + $get = $gets{$base} or die "No get for '$base'"; + + if($array) { + $get =~ s/__TARG__/${name}\l[i]/g; + $get =~ s/__SRC__/s/g; + $get =~ s/__SRCCELL__/c/g; + $get = qq* + // count rank + int i=-1; + for(ZZCell c = n; c!=null; c=c.s("d.1")) i++; + // XXX check range + $name = new ${base}\l[i]; + i=0; + for(ZZCell c = n.s("d.1"); + c!=null; c=c.s("d.1")) { + s = c.getText(); + $get; + i++; + } + *; + } else { + $get =~ s/__TARG__/$name/g; + $get =~ s/__SRC__/s/g; + $get =~ s/__SRCCELL__/c/g; + $get = qq{ZZCell c = n.s("d.1"); s = c.getText(); $get }; + } + + $curbit ++; + $curmask = (1 << $curbit); + + $tests .= qq* + if(s.equals("$name")) { + mask |= $curmask; + try { + $get + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + +*; +} + +$fullmask = (1<<($curbit+1))-1; + +# print "PARAMS: (",(join '||||||',@pars),")\n"; + +# limit of 31 variables for now. + +$code = <$outfile" or die "No out: '$outfile'"; +print OUT $str; +close OUT; diff --git a/LICENSE.lgpl b/LICENSE.lgpl new file mode 100644 index 0000000..92b8903 --- /dev/null +++ b/LICENSE.lgpl @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/LICENSE.xpl b/LICENSE.xpl new file mode 100644 index 0000000..388f365 --- /dev/null +++ b/LICENSE.xpl @@ -0,0 +1,16 @@ +This is version 0 of the Xanadu Public License (XPL). +This version of this license does not grant you any rights beyond +those you would have without it. There is no warranty, express or implied, +not even the warranty of merchantability or fitness for any particular +purpose. + +((Rationale, NOT PART OF THE ACTUAL LICENSE: +This is a placeholder for version 1 of the license which is going to +be Ted Nelson's transpublishing-based opensource license. +For the gzigzag package, the existence of this placeholder means two things: +1) Currently the distribution mode is exactly LGPL, due to the user's other +choice being this license which is currently nothing +2) When submitting contributions, you are implicitly agreeing that your +contributions will fall under the later versions of this license as well as +LGPL, when incorporated into gzigzag.)) + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9bf3735 --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ + +all : + @echo "Please cd to a subdirectory first (see README)." + @exit 1 + +CVS=cvs +Manifest: + rm -f $@.new $@.edi + ./cvsparser.pl | ./manifest-filter.pl > $@.edi + sort $@.edi -o $@.new + mv $@.new $@ + rm -f $@.edi + +VERSION=snapshot-`date -u +%Y%m%d` +TAG="Unofficial" + +dist : DISTDIR=gzigzag-$(VERSION) +dist : dist.tgz dist.zip + +dist.tgz : distdir + tar cf $(DISTDIR).tar $(DISTDIR) + gzip -9vf $(DISTDIR).tar + +dist.zip : distdir + zip -r9 $(DISTDIR).zip $(DISTDIR) + +release : DISTDIR=gzigzag-$(VERSION) +release : modulesupport.jar + $(MAKE) dist + $(MAKE) -C Java MODULESUPPORT=$(shell pwd)/modulesupport.jar \ + BUILD_TAG="$(TAG) $(VERSION) (with modules)" \ + JARNAME=$(DISTDIR)-with-modules.jar jar + mv Java/$(DISTDIR)-with-modules.jar . + $(MAKE) -C Java MODULES="" \ + BUILD_TAG="$(TAG) $(VERSION) (without modules)" \ + JARNAME=$(DISTDIR)-without-modules.jar jar + mv Java/$(DISTDIR)-without-modules.jar . + $(MAKE) -C Documentation dist + mv Documentation/docdisttree $(DISTDIR)-doc + tar cf $(DISTDIR)-doc.tar $(DISTDIR)-doc + gzip -9vf $(DISTDIR)-doc.tar + zip -r9 $(DISTDIR)-doc.zip $(DISTDIR)-doc + rm -f $(DISTDIR).md5sums.new + set -e; for f in $(DISTDIR)-without-modules.jar \ + $(DISTDIR)-with-modules.jar \ + $(DISTDIR).tar.gz \ + $(DISTDIR).zip \ + $(DISTDIR)-doc.tar.gz \ + $(DISTDIR)-doc.zip; \ + do \ + sum=$$(md5sum $$f | awk '{ print $$1; }'); \ + size=$$(ls -l $$f | awk '{ print $$5; }'); \ + echo "$$sum $$size $$f" >> $(DISTDIR).md5sums.new; \ + done + mv $(DISTDIR).md5sums.new $(DISTDIR).md5sums + rm -rf docdisttree + +CVSTAG=none +official-release : VERSION=$(shell echo $(CVSTAG) \ + | sed -e 's/^rel_//' -e 's/_/./g') +official-release : grbdir=gzigzag-release-build +official-release : modulesupport.jar + rm -rf $(grbdir) + set -e ;\ + if $$(echo $(VERSION) \ + | egrep '^[0-9]+\.[0-9]+\.(pre)?[0-9]+$$' >/dev/null);\ + then\ + :; \ + else \ + echo "Bad VERSION"; \ + exit 1; \ + fi + cvs -z3 -d$(shell cat CVS/Root) checkout -r $(CVSTAG) \ + -d $(grbdir) gzigzag + ln modulesupport.jar $(grbdir) + make -C $(grbdir) VERSION=$(VERSION) TAG="Official" release + ln -f $(grbdir)/gzigzag-$(VERSION)-with-modules.jar + ln -f $(grbdir)/gzigzag-$(VERSION)-without-modules.jar + ln -f $(grbdir)/gzigzag-$(VERSION).tar.gz + ln -f $(grbdir)/gzigzag-$(VERSION).zip + ln -f $(grbdir)/gzigzag-$(VERSION)-doc.tar.gz + ln -f $(grbdir)/gzigzag-$(VERSION)-doc.zip + ln -f $(grbdir)/gzigzag-$(VERSION).md5sums + rm -rf $(grbdir) + + +DISTDIR=gzigzag-dist +distdir: + ./makedist.sh $(DISTDIR) + +CVS2CL=cvs2cl + +ChangeLog :: + CVS_RSH=ssh $(CVS2CL) -U changelog-authors -l -d'2001-01-01\ + +GZigZag + + + +Unbelievably cool GZigZag demo. + + + + + diff --git a/Modules/awtool/AwtCursor.java b/Modules/awtool/AwtCursor.java new file mode 100644 index 0000000..72ec672 --- /dev/null +++ b/Modules/awtool/AwtCursor.java @@ -0,0 +1,36 @@ +/* +AwtCursor.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +public class AwtCursor { + Color color; + boolean shared; + public AwtCursor(Color cursorColor, boolean shared) { + color = cursorColor; + this.shared = shared; + } +} diff --git a/Modules/awtool/AwtLink.java b/Modules/awtool/AwtLink.java new file mode 100644 index 0000000..0153902 --- /dev/null +++ b/Modules/awtool/AwtLink.java @@ -0,0 +1,176 @@ +/* DO NOT EDIT THIS FILE. THIS FILE WAS GENERATED FROM ../Modules/awtool/AwtLink.zob, + * EDIT THAT FILE INSTEAD! + * All changes to this file will be lost. + */ +/* +AwtLink.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; + + +public class AwtLink extends ZObCellRepr implements ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + /** UNDOCUMENTED. + + *

    Default value:

     0.0;
    . + + * @structparam 1 + */ + + public + double x + = 0.0;/** UNDOCUMENTED. + + *

    Default value:

     0.0;
    . + + * @structparam 1 + */ + + public double y + = 0.0;/** UNDOCUMENTED. + + *

    Default value:

     false;
    . + + * @structparam 1 + */ + + public boolean fixed + = false; + + + /* AUTOGENERATED! */ + static final private int fullmask = 7; + + /* AUTOGENERATED! */ + public String readParams(ZZCell start) { + int m = 0; + try { + if(start != null) + m = readParams(start, 0); + } catch(Throwable t) { + ZZLogger.exc(t); + } finally { + + } + if((m & fullmask) != fullmask) { + // not all parameters present - no problem right now. + } + return ""; + } + + /* AUTOGENERATED! */ + private int readParams(ZZCell start, int mask) { + ZZCell n = start; + while(n != null) { + String s = n.getText(); + // Tests autogenerated from members. + + if(s.equals("x")) { + mask |= 1; + try { + ZZCell c = n.s("d.1"); s = c.getText(); x = (Double.valueOf(s)).doubleValue(); + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("y")) { + mask |= 2; + try { + ZZCell c = n.s("d.1"); s = c.getText(); y = (Double.valueOf(s)).doubleValue(); + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("fixed")) { + mask |= 4; + try { + ZZCell c = n.s("d.1"); s = c.getText(); + if(s.equals("true")) fixed=true; + else if(s.equals("false")) fixed=false; + else { /* XXX ??? */ } + + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + { } // grab that last "else" + ZZCell h = n.h("d.3"); + if(h != null && h != n) { + // recurse + mask |= readParams(h, mask); + } + n = n.s("d.2"); + } + return mask; + } + + + + public boolean isFixed() { return fixed; } + + public void setX(double x) { this.x = x; } + public void setY(double y) { this.y = y; } + + public double getX() { return x; } + public double getY() { return y; } + + public ZZCell toHeadCell() { + return getCell().h(AwtUtil.d_from, 1).h(AwtUtil.d_clone); + } + + public ZZCell fromHeadCell() { + return getCell().h(AwtUtil.d_to).h(AwtUtil.d_clone); + } + + public String getZObName() { + return "Link"; + } + + public String cellRepr(ZZCell start, boolean clone) + { + ZZCell c = start.getOrNewCell("d.1"); + c.setText(getZObClassName()); + c = c.getOrNewCell("d.1"); + c.setText("x"); + c.getOrNewCell("d.1").setText(""+getX()); + c = c.getOrNewCell("d.2"); + c.setText("y"); + c.getOrNewCell("d.1").setText(""+getY()); + return ""; + } +} + +// vim: set syntax=java : diff --git a/Modules/awtool/AwtLink.zob b/Modules/awtool/AwtLink.zob new file mode 100644 index 0000000..f6d307d --- /dev/null +++ b/Modules/awtool/AwtLink.zob @@ -0,0 +1,80 @@ +/* +AwtLink.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; + + +public class AwtLink extends ZObCellRepr implements ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + double x + = 0.0; + + double y + = 0.0; + + boolean fixed + = false; + } + + public boolean isFixed() { return fixed; } + + public void setX(double x) { this.x = x; } + public void setY(double y) { this.y = y; } + + public double getX() { return x; } + public double getY() { return y; } + + public ZZCell toHeadCell() { + return getCell().h(AwtUtil.d_from, 1).h(AwtUtil.d_clone); + } + + public ZZCell fromHeadCell() { + return getCell().h(AwtUtil.d_to).h(AwtUtil.d_clone); + } + + public String getZObName() { + return "Link"; + } + + public String cellRepr(ZZCell start, boolean clone) + { + ZZCell c = start.getOrNewCell("d.1"); + c.setText(getZObClassName()); + c = c.getOrNewCell("d.1"); + c.setText("x"); + c.getOrNewCell("d.1").setText(""+getX()); + c = c.getOrNewCell("d.2"); + c.setText("y"); + c.getOrNewCell("d.1").setText(""+getY()); + return ""; + } +} + +// vim: set syntax=java : diff --git a/Modules/awtool/AwtMetrics.java b/Modules/awtool/AwtMetrics.java new file mode 100644 index 0000000..b7a352e --- /dev/null +++ b/Modules/awtool/AwtMetrics.java @@ -0,0 +1,502 @@ +/* DO NOT EDIT THIS FILE. THIS FILE WAS GENERATED FROM ../Modules/awtool/AwtMetrics.zob, + * EDIT THAT FILE INSTEAD! + * All changes to this file will be lost. + */ +/* +AwtMetrics.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** Abstract class for different metrics (in order to get different + * focus+context effects) + */ + +public abstract class AwtMetrics extends ZObCellRepr implements ZOb { + public static boolean dbg = true; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + + /** UNDOCUMENTED. + + *

    Default value:

     { 400, 400 };
    . + + * @structparam 1 + */ + + public + int[] RealView + = { 400, 400 };/** UNDOCUMENTED. + + *

    Default value:

     { 400, 400 };
    . + + * @structparam 1 + */ + + public int[] VirtualView + = { 400, 400 };/** UNDOCUMENTED. + + *

    Default value:

     { 0.0, 0.0 };
    . + + * @structparam 1 + */ + + public double[] Origo + = { 0.0, 0.0 };/** UNDOCUMENTED. + + *

    Default value:

     { 200, 200 };
    . + + * @structparam 1 + */ + + public int[] FocusOrigo + = { 200, 200 };/** UNDOCUMENTED. + + *

    Default value:

     true;
    . + + * @structparam 1 + */ + + public boolean GridOn + = true; + + /* AUTOGENERATED! */ + static final private int fullmask = 31; + + /* AUTOGENERATED! */ + public String readParams(ZZCell start) { + int m = 0; + try { + if(start != null) + m = readParams(start, 0); + } catch(Throwable t) { + ZZLogger.exc(t); + } finally { + + } + if((m & fullmask) != fullmask) { + // not all parameters present - no problem right now. + } + return ""; + } + + /* AUTOGENERATED! */ + private int readParams(ZZCell start, int mask) { + ZZCell n = start; + while(n != null) { + String s = n.getText(); + // Tests autogenerated from members. + + if(s.equals("RealView")) { + mask |= 1; + try { + + // count rank + int i=-1; + for(ZZCell c = n; c!=null; c=c.s("d.1")) i++; + // XXX check range + RealView = new int[i]; + i=0; + for(ZZCell c = n.s("d.1"); + c!=null; c=c.s("d.1")) { + s = c.getText(); + RealView[i] = Integer.parseInt(s); ; + i++; + } + + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("VirtualView")) { + mask |= 2; + try { + + // count rank + int i=-1; + for(ZZCell c = n; c!=null; c=c.s("d.1")) i++; + // XXX check range + VirtualView = new int[i]; + i=0; + for(ZZCell c = n.s("d.1"); + c!=null; c=c.s("d.1")) { + s = c.getText(); + VirtualView[i] = Integer.parseInt(s); ; + i++; + } + + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("Origo")) { + mask |= 4; + try { + + // count rank + int i=-1; + for(ZZCell c = n; c!=null; c=c.s("d.1")) i++; + // XXX check range + Origo = new double[i]; + i=0; + for(ZZCell c = n.s("d.1"); + c!=null; c=c.s("d.1")) { + s = c.getText(); + Origo[i] = (Double.valueOf(s)).doubleValue();; + i++; + } + + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("FocusOrigo")) { + mask |= 8; + try { + + // count rank + int i=-1; + for(ZZCell c = n; c!=null; c=c.s("d.1")) i++; + // XXX check range + FocusOrigo = new int[i]; + i=0; + for(ZZCell c = n.s("d.1"); + c!=null; c=c.s("d.1")) { + s = c.getText(); + FocusOrigo[i] = Integer.parseInt(s); ; + i++; + } + + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("GridOn")) { + mask |= 16; + try { + ZZCell c = n.s("d.1"); s = c.getText(); + if(s.equals("true")) GridOn=true; + else if(s.equals("false")) GridOn=false; + else { /* XXX ??? */ } + + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + { } // grab that last "else" + ZZCell h = n.h("d.3"); + if(h != null && h != n) { + // recurse + mask |= readParams(h, mask); + } + n = n.s("d.2"); + } + return mask; + } + + + + static ZZCell FocusedCell = null; + + double FocusCoefficient = focusCoefficientMinimum(); + + abstract double focusCoefficientMinimum(); + abstract double focusCoefficientMaximum(); + + public double[] RealViewd() { + return new double[] { (double)RealView[0], (double)RealView[1] }; + } + + public double[] RealViewHalfd() { + return new double[] { (double)RealView[0]*0.5, (double)RealView[1]*0.5 }; + } + + public void setRealView(int x, int y, boolean adjustFocus) { + if(adjustFocus) { + double[] rvd = RealViewd(); + double newfox = ((double)(x*FocusOrigo[0]))/rvd[0]; + double newfoy = ((double)(y*FocusOrigo[1]))/rvd[1]; + setFocusOrigo((int)newfox, (int)newfoy); + } + RealView[0] = x; RealView[1] = y; + } + + public void setRealView(Dimension d, boolean adjustFocus) { + setRealView(d.width, d.height, adjustFocus); + } + public double[] VirtualViewd() { + return new double[] { (double)VirtualView[0], (double)VirtualView[1] }; + } + + public double[] VirtualViewHalfd() { + return new double[] { (double)VirtualView[0]*0.5, (double)VirtualView[1]*0.5 }; + } + + public void setVirtualView(int x, int y) { + VirtualView[0] = x; VirtualView[1] = y; + } + + public void setOrigo(double ox, double oy) { + Origo[0] = ox; + Origo[1] = oy; + } + + public void moveOrigo(double dox, double doy) { + Origo[0] += dox; + Origo[1] += doy; + } + + public double[] FocusOrigod() { + return new double[] { (double)FocusOrigo[0], (double)FocusOrigo[1] }; + } + + + public void setFocusOrigo(int fox, int foy) { + setFocusOrigo(fox, foy, null); + } + + public void setFocusOrigo(int fox, int foy, ZZCell focusCell) { + FocusOrigo[0] = fox; + FocusOrigo[1] = foy; + if(focusCell != null && focusCell == FocusedCell) { + FocusCoefficient += 1.0; + if(FocusCoefficient > focusCoefficientMaximum()) + FocusCoefficient = focusCoefficientMaximum(); + } else { + FocusCoefficient = focusCoefficientMinimum(); + FocusedCell = focusCell; + } + } + + + public void init(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) { + setCell(start); + setRealView(rv.width, rv.height, false); + setVirtualView(vv.width, vv.height); + setOrigo(ox, oy); + setFocusOrigo(rv.width>>1, rv.height>>1); + } + + public AwtMetrics() { } + + public AwtMetrics(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) + { + init(start, rv, vv, ox, oy); + + } + + private Point mapToUnfocusedRealView(double x, double y) { + int rx, ry; + double[] vvhd = VirtualViewHalfd(), rvhd = RealViewHalfd(); + rx = (int)(( (x-Origo[0]) * vvhd[0]) + rvhd[0]); + ry = (int)(( (y-Origo[1]) * vvhd[1]) + rvhd[1]); + return new Point(rx, ry); + } + + /** mapping from 'virtualview' (=modelview, coordinates + * -1.0 focusCoefficientMaximum()) + FocusCoefficient = focusCoefficientMaximum(); + } else { + FocusCoefficient = focusCoefficientMinimum(); + FocusedCell = focusCell; + } + } + + + public void init(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) { + setCell(start); + setRealView(rv.width, rv.height, false); + setVirtualView(vv.width, vv.height); + setOrigo(ox, oy); + setFocusOrigo(rv.width>>1, rv.height>>1); + } + + public AwtMetrics() { } + + public AwtMetrics(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) + { + init(start, rv, vv, ox, oy); + + } + + private Point mapToUnfocusedRealView(double x, double y) { + int rx, ry; + double[] vvhd = VirtualViewHalfd(), rvhd = RealViewHalfd(); + rx = (int)(( (x-Origo[0]) * vvhd[0]) + rvhd[0]); + ry = (int)(( (y-Origo[1]) * vvhd[1]) + rvhd[1]); + return new Point(rx, ry); + } + + /** mapping from 'virtualview' (=modelview, coordinates + * -1.0-1) { + dx = x2; + } else { + dx = x2*x2; + dx = x2>0 ? dx : -dx; + } + + if(y2<1 && y2>-1) { + dy = y2; + } else { + dy = y2*y2; + dy = y2>0 ? dy : -dy; + } + + return new double[] { dx/focusCoeff, dy/focusCoeff }; + } + + public double[] inverseTransformAtFocusNbhood(double x, double y, double focusCoeff) { + double dx, dy, x2, y2; + + x2 = x*focusCoeff; + y2 = y*focusCoeff; + + if(x2<1 && x2>-1) { + dx = x2; + } else { + dx = (x2>0) ? Math.sqrt(x2) : -Math.sqrt(-x2); + } + + if(y2<1 && y2>-1) { + dy = y2; + } else { + dy = (y2>0) ? Math.sqrt(y2) : -Math.sqrt(-y2); + } + + return new double[] { dx/focusCoeff, dy/focusCoeff }; + } + + public double transformScalingValue(double s) { return 1.0/s; } + + public double focusCoefficientMinimum() { return 4.0; } + public double focusCoefficientMaximum() { return 8.0; } + + public AwtMetricsFC() { super(); } + + public AwtMetricsFC(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) { + super(start, rv, vv, ox, oy); + } +} + diff --git a/Modules/awtool/AwtMetricsFC2.java b/Modules/awtool/AwtMetricsFC2.java new file mode 100644 index 0000000..252357c --- /dev/null +++ b/Modules/awtool/AwtMetricsFC2.java @@ -0,0 +1,94 @@ +/* +AwtMetricsFC2.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** Focus+context metrics2 + */ + + +public class AwtMetricsFC2 extends AwtMetrics { + public String getZObName() { + return "Focus+Context (2)"; + } + + public double[] transformAtFocusNbhood(double x, double y, double focusCoeff) { + double dx, dy, x2, y2; + + x2 = x*focusCoeff; + y2 = y*focusCoeff; + + if(x2<1 && x2>-1) { + dx = x2; + } else { + dx = (x2>0) ? Math.sqrt(x2) : -Math.sqrt(-x2); + } + + if(y2<1 && y2>-1) { + dy = y2; + } else { + dy = (y2>0) ? Math.sqrt(y2) : -Math.sqrt(-y2); + } + + return new double[] { dx/focusCoeff, dy/focusCoeff }; + } + + public double[] inverseTransformAtFocusNbhood(double x, double y, double focusCoeff) { + double dx, dy, x2, y2; + + x2 = x*focusCoeff; + y2 = y*focusCoeff; + + if(x2<1 && x2>-1) { + dx = x2; + } else { + dx = x2*x2; + dx = x2>0 ? dx : -dx; + } + + if(y2<1 && y2>-1) { + dy = y2; + } else { + dy = y2*y2; + dy = y2>0 ? dy : -dy; + } + + return new double[] { dx/focusCoeff, dy/focusCoeff }; + } + + public double transformScalingValue(double s) { return s; } + + public double focusCoefficientMinimum() { return 4.0; } + public double focusCoefficientMaximum() { return 8.0; } + + public AwtMetricsFC2() { super(); } + + public AwtMetricsFC2(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) { + super(start, rv, vv, ox, oy); + } +} + diff --git a/Modules/awtool/AwtMetricsNormal.java b/Modules/awtool/AwtMetricsNormal.java new file mode 100644 index 0000000..bbc6680 --- /dev/null +++ b/Modules/awtool/AwtMetricsNormal.java @@ -0,0 +1,58 @@ +/* +AwtMetricsNormal.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** Default metrics: Euclidean, no focus+context (no scaling) + */ + + +public class AwtMetricsNormal extends AwtMetrics { + public String getZObName() { + return "Normal(Euclidean)"; + } + + public double[] transformAtFocusNbhood(double x, double y, double focusCoeff) { + return new double[] { x, y }; + } + + public double[] inverseTransformAtFocusNbhood(double x, double y, double focusCoeff) { + return new double[] { x, y }; + } + + public double transformScalingValue(double s) { return 1.0; } + + public double focusCoefficientMinimum() { return 1.0; } + public double focusCoefficientMaximum() { return 1.0; } + + public AwtMetricsNormal() { super(); } + + public AwtMetricsNormal(ZZCell start, Dimension rv, Dimension vv, + double ox, double oy) { + super(start, rv, vv, ox, oy); + } +} + diff --git a/Modules/awtool/AwtNileView.java b/Modules/awtool/AwtNileView.java new file mode 100644 index 0000000..e73b4f3 --- /dev/null +++ b/Modules/awtool/AwtNileView.java @@ -0,0 +1,110 @@ +/* +AwtNileView.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Nile1View.java written by Tuomas Lukka, + * AwtNileView - localization for Awtool by Kimmo Wideroos + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; +import java.io.*; + +/** A view for nile streams. + */ + +public class AwtNileView extends Nile1View { +public static final String rcsid = ""; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + public AwtNileView() { + init__zob(); + } + + public void awtNileRaster(FlobSet into, ZZCell view, ZZCell accursed, + Rectangle rect) { + int[] offs = new int[1]; + + LoopDetector ld = new LoopDetector(); + + ZZCursor selectEnd = null; + ZZCell sele = view.s("d.nile-sel"); + if(sele != null) { + selectEnd = ZZCursorVirtual.createFromReal(sele); + } + + // Do the center paragraph first. + ZZCell firstpara = Nile2Iter.findStruct(accursed, -1, true); + ZZCell nextpara = Nile2Iter.findStruct(accursed, 1, false); + + FText ft = paragraph(firstpara, nextpara, new ZZCursorReal(view), + offs, selectEnd); + + Dimension size = new Dimension(rect.width, rect.height); + //Rectangle rect = new Rectangle(0, 0, size.width, size.height); + + Rectangle ctr = placeParagraph(into, ft, firstpara, rect, + 0, rect.y+rect.height/2, + ZZCursorReal.getVisualTextOffset(view)); + + // Go into positive direction. + Rectangle r = ctr; + while(nextpara != null) { + ld.detect(nextpara); + ZZCell next = Nile2Iter.findStruct(nextpara, 1, false); + ft = paragraph(nextpara, next, null, null, selectEnd); + + r = placeParagraph(into, ft, nextpara, rect, + 1, r.y+r.height + paraskip, 0); + + nextpara = next; + + if(r.y + r.height > size.height) break; + } + + // And negative. + r = ctr; + while(true) { + ZZCell prev = firstpara; + firstpara = Nile2Iter.findStruct(firstpara, -1, false); + if(firstpara == null) break; + ld.detect(firstpara); + + ft = paragraph(firstpara, prev, null, null, null); + + beginningSentence[0] = true; + r = placeParagraph(into, ft, firstpara, rect, + -1, r.y - paraskip, 0); + + if(r.y < 0) break; + } + // into.dump(); + Flob cursf = into.findFlob(null, accursed); + // p("Cursf: "+cursf); + if(cursf != null) + ((SplitCellFlob1)cursf).addCurs(into, ZZCursorReal.getOffs(view), + Color.red); + } +} + + +// vim: set syntax=java : diff --git a/Modules/awtool/AwtNote.java b/Modules/awtool/AwtNote.java new file mode 100644 index 0000000..d04bdf9 --- /dev/null +++ b/Modules/awtool/AwtNote.java @@ -0,0 +1,212 @@ +/* DO NOT EDIT THIS FILE. THIS FILE WAS GENERATED FROM ../Modules/awtool/AwtNote.zob, + * EDIT THAT FILE INSTEAD! + * All changes to this file will be lost. + */ +/* +Awtnote.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; + +/** this is for awt content. change 'AwtNote' => 'AwtContent' +*/ + + +public class AwtNote extends ZObCellRepr implements ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + /** UNDOCUMENTED. + + *

    Default value:

     0.1;
    . + + * @structparam 1 + */ + + public + double width + = 0.1;/** UNDOCUMENTED. + + *

    Default value:

     0.07;
    . + + * @structparam 1 + */ + + public double height + = 0.07; + + + /* AUTOGENERATED! */ + static final private int fullmask = 3; + + /* AUTOGENERATED! */ + public String readParams(ZZCell start) { + int m = 0; + try { + if(start != null) + m = readParams(start, 0); + } catch(Throwable t) { + ZZLogger.exc(t); + } finally { + + } + if((m & fullmask) != fullmask) { + // not all parameters present - no problem right now. + } + return ""; + } + + /* AUTOGENERATED! */ + private int readParams(ZZCell start, int mask) { + ZZCell n = start; + while(n != null) { + String s = n.getText(); + // Tests autogenerated from members. + + if(s.equals("width")) { + mask |= 1; + try { + ZZCell c = n.s("d.1"); s = c.getText(); width = (Double.valueOf(s)).doubleValue(); + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + if(s.equals("height")) { + mask |= 2; + try { + ZZCell c = n.s("d.1"); s = c.getText(); height = (Double.valueOf(s)).doubleValue(); + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + { } // grab that last "else" + ZZCell h = n.h("d.3"); + if(h != null && h != n) { + // recurse + mask |= readParams(h, mask); + } + n = n.s("d.2"); + } + return mask; + } + + + + // category link + private AwtLink cLink = null; + double x = Double.NaN; + double y = Double.NaN; + + public void setCell(ZZCell c) { + super.setCell(c); + ZZCell cc, nCategoryCell = AwtUtil.getNoteCellCategory(c); + if(nCategoryCell != null) { + cc = c.s(AwtUtil.d_from, -1); + if(cc.s("d.1") != null) + cLink = (AwtLink)AwtUtil.readZObClone(cc); + else + cLink = new AwtLink(); + cLink.setCell(cc); + } else { + cLink = new AwtLink(); + } + } + + public double getWidth() { return width; } + public double getHeight() { return height; } + + public double[] getDimension() { return new double[] { width, height }; } + public void setDimension(double w, double h) { + width = w; + height = h; + } + + public AwtLink getCategoryLink() { + return cLink; + } + + public void setCategoryLink(AwtLink cl) { + cLink = cl; + } + + public void setCoord(double x, double y) { + cLink.setX(x); + cLink.setY(y); + } + + public void setX(double x) { + cLink.setX(x); + } + + public void setY(double y) { + cLink.setY(y); + } + + public double[] getCoord() { + return new double[] { cLink.getX(), cLink.getY() }; + } + + public double getX() { + return cLink.getX(); + } + public double getY() { + return cLink.getY(); + } + + public String getZObName() { + return "Note"; + } + + /** method for storing ZOb back to structure. + * @param start quess;) + * @param clone whether or not to make the new central cell a clone of + * this.cell (default is true). + */ + public String cellRepr(ZZCell start, boolean clone) + { + ZZCell c = start.getOrNewCell("d.1"); + c.setText(getZObClassName()); + c.setText("AwtNote"); + c = c.getOrNewCell("d.1"); + c.setText("width"); + c.getOrNewCell("d.1").setText(""+getWidth()); + c = c.getOrNewCell("d.2"); + c.setText("height"); + c.getOrNewCell("d.1").setText(""+getHeight()); + if(clone && !start.equals(getCell())) { + getCell().connect(AwtUtil.d_clone, start); + } + if(cLink.getCell() != null) cLink.cellRepr(); + return ""; + } +} + +// vim: set syntax=java : diff --git a/Modules/awtool/AwtNote.zob b/Modules/awtool/AwtNote.zob new file mode 100644 index 0000000..6b47d30 --- /dev/null +++ b/Modules/awtool/AwtNote.zob @@ -0,0 +1,135 @@ +/* +Awtnote.java + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; + +/** this is for awt content. change 'AwtNote' => 'AwtContent' +*/ + + +public class AwtNote extends ZObCellRepr implements ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + double width + = 0.1; + + double height + = 0.07; + } + + // category link + private AwtLink cLink = null; + double x = Double.NaN; + double y = Double.NaN; + + public void setCell(ZZCell c) { + super.setCell(c); + ZZCell cc, nCategoryCell = AwtUtil.getNoteCellCategory(c); + if(nCategoryCell != null) { + cc = c.s(AwtUtil.d_from, -1); + if(cc.s("d.1") != null) + cLink = (AwtLink)AwtUtil.readZObClone(cc); + else + cLink = new AwtLink(); + cLink.setCell(cc); + } else { + cLink = new AwtLink(); + } + } + + public double getWidth() { return width; } + public double getHeight() { return height; } + + public double[] getDimension() { return new double[] { width, height }; } + public void setDimension(double w, double h) { + width = w; + height = h; + } + + public AwtLink getCategoryLink() { + return cLink; + } + + public void setCategoryLink(AwtLink cl) { + cLink = cl; + } + + public void setCoord(double x, double y) { + cLink.setX(x); + cLink.setY(y); + } + + public void setX(double x) { + cLink.setX(x); + } + + public void setY(double y) { + cLink.setY(y); + } + + public double[] getCoord() { + return new double[] { cLink.getX(), cLink.getY() }; + } + + public double getX() { + return cLink.getX(); + } + public double getY() { + return cLink.getY(); + } + + public String getZObName() { + return "Note"; + } + + /** method for storing ZOb back to structure. + * @param start quess;) + * @param clone whether or not to make the new central cell a clone of + * this.cell (default is true). + */ + public String cellRepr(ZZCell start, boolean clone) + { + ZZCell c = start.getOrNewCell("d.1"); + c.setText(getZObClassName()); + c.setText("AwtNote"); + c = c.getOrNewCell("d.1"); + c.setText("width"); + c.getOrNewCell("d.1").setText(""+getWidth()); + c = c.getOrNewCell("d.2"); + c.setText("height"); + c.getOrNewCell("d.1").setText(""+getHeight()); + if(clone && !start.equals(getCell())) { + getCell().connect(AwtUtil.d_clone, start); + } + if(cLink.getCell() != null) cLink.cellRepr(); + return ""; + } +} + +// vim: set syntax=java : diff --git a/Modules/awtool/AwtUtil.java b/Modules/awtool/AwtUtil.java new file mode 100644 index 0000000..f1e7d4d --- /dev/null +++ b/Modules/awtool/AwtUtil.java @@ -0,0 +1,329 @@ +/* +AwtUtil.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** Some general stuff + */ + +public class AwtUtil { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + public static String d_to="d.map-1"; + public static String d_from="d.map-2"; + public static String d_categories="d.categories"; + public static String d_notes="d.notes"; + public static String d_awtool="d.awtool"; + + public static String d_clone="d.clone"; + + public static ZZCell addDims(ZZCell defaultDimsBegin) { + Hashtable awtDims = new Hashtable(); + + awtDims.put(d_to, d_to); + awtDims.put(d_from, d_from); + awtDims.put(d_categories, d_categories); + awtDims.put(d_notes, d_notes); + awtDims.put(d_awtool, d_awtool); + + String dim; + + for(ZZCell c = defaultDimsBegin; c != null; c = c.s("d.2") ) { + dim = c.getText(); + if(awtDims.containsKey(dim)) + awtDims.remove(dim); + if(c.equals(defaultDimsBegin.s("d.2", -1))) break; + } + + for(Enumeration e = awtDims.keys(); e.hasMoreElements(); ) { + dim = (String)e.nextElement(); + defaultDimsBegin.N("d.2", -1).setText(dim); + } + return defaultDimsBegin; + } + + /** return awt system list roocell + */ + public static ZZCell getAwtSysList(ZZCell vc) { + ZZCell awtc = ZZDefaultSpace.findInheritableParam(vc, "AwtSystemList"); + if(awtc == null) return null; + return ZZCursorReal.get(awtc); + } + + /** return active metrics + */ + public static AwtMetrics getAwtMetrics(ZZCell awtsyslist) { + ZZCell metr = getCursoredCell(Awtool.c_metrics, awtsyslist); + if(metr==null) { + metr = awtsyslist.findText(d_awtool, 1, "Metrics"); + if(metr!=null) metr = metr.s("d.1"); + } + if(metr == null) throw new ZZError("Awtool: Couldn't initialize metrics!!"); + AwtMetrics M = (AwtMetrics)readZObClone(metr); + M.setCell(metr); + return M; + } + + public static ZZCell getCursoredCell(AwtCursor acur, ZZCell viewcellOrAwtsyslist) { + String cursorName = acur.color.toString(); + ZZCell awtsyslist, vc, cur=null, cursors; + + // scrutinize 'viewcellOrAwtsyslist' + if(viewcellOrAwtsyslist.getRankLength(d_awtool)>1) { + awtsyslist = viewcellOrAwtsyslist; + vc = null; + } else { + vc = viewcellOrAwtsyslist; + awtsyslist = getAwtSysList(vc); + } + + // shared cursors belongs to all awtool views + if(!acur.shared) { + cursors = awtsyslist.findText(d_awtool, 1, "Cursors").s("d.1"); + cur = cursors.findText("d.2", 1, cursorName); + } else { + ZZCell scursors, win, vcShared; + ZZCell[] wins; + ZZSpace sp = vc.getSpace(); + win = ZZDefaultSpace.findOnSystemlist(sp, "Windows", false); + win = win.s("d.1"); + wins = AwtUtil.findAll(win, "d.2", 1, "awtool"); + if(wins==null) throw new ZZError("Awtool: No awtool window found!!"); + for(int i=0; i1) { + awtsyslist = viewcellOrAwtsyslist; + vc = null; + } else { + vc = viewcellOrAwtsyslist; + awtsyslist = getAwtSysList(vc); + } + + // shared cursors belongs to all awtool views + if(!acur.shared) { + cursors = awtsyslist.findText(d_awtool, 1, "Cursors").s("d.1"); + cur = cursors.findText("d.2", 1, cursorName); + } else { + ZZCell win, vcShared; + ZZCell[] wins; + ZZSpace sp = vc.getSpace(); + win = ZZDefaultSpace.findOnSystemlist(sp, "Windows", false); + win = win.s("d.1"); + wins = AwtUtil.findAll(win, "d.2", 1, "awtool"); + if(wins==null) throw new ZZError("Awtool: No awtool window found!!"); + for(int i=0; i=0; i--) { + fc[i] = (ZZCell)found.elementAt(i); + } + return fc; + } + + public interface ObjectComparator { + int compare(Object o1, Object o2); + } + + public static void quickSort(Vector a, int lo0, int hi0, ObjectComparator c) { + int lo = lo0; + int hi = hi0; + + if (lo >= hi) + return; + + Object mid = a.elementAt((lo + hi) / 2); + while (lo < hi) { + while (lo 0) + hi--; + if (lo < hi) { + Object T = a.elementAt(lo); + a.setElementAt(a.elementAt(hi), lo); + a.setElementAt(T, hi); + lo++; + hi--; + } + } + if (hi < lo) { + int T = hi; + hi = lo; + lo = T; + } + quickSort(a, lo0, lo, c); + quickSort(a, lo == lo0 ? lo+1 : lo, hi0, c); + } + + /** Construct and return a ZOb of the given type. + */ + public static ZOb newModuleZOb(String id) { + // XXX Figure out if we can cache something. + // XXX Should ZOb be able to reset? Easier or less easy than + // recreate? At least ZObs should cache... + try { + Class z = Class.forName("org.gzigzag.module."+id); + return (ZOb)Class.forName("org.gzigzag.module."+id).newInstance(); + } catch(Exception e) { + ZZLogger.exc(e); + return null; + } + } + + /** Construct a ZOb corresponding to a cell and read the params. + * DOES NOT Go to the rootclone, takes the next cell on d.1 as the ZOb's name, + * and takes the NEXT cell on d.1 as the head of the list from which to + * read the structparams. + */ + static public ZOb readZObClone(ZZCell start) { + //ZZCell c = start.h("d.clone", -1).s("d.1", 1); + + if(start.s("d.1") == null) start = start.h("d.clone", -1); + ZZCell c = start.s("d.1", 1); + if(c == null) + throw new ZZError("Error reading ZOb from cell "+start.getText()); + ZOb z = newModuleZOb(c.getText()); + z.readParams(c.s("d.1", 1)); + return z; + } + + /** return category cell of the note c + */ + static public ZZCell getNoteCellCategory(ZZCell c) { + ZZCell qwerty = c.s(d_from, -1); + if(qwerty == null) return null; + if(qwerty.equals(qwerty.h(d_to, -1))) return null; + qwerty = qwerty.h(d_to, -1); + if(qwerty.getRankLength(d_categories) == 1) return null; + return qwerty; + } + + static public AwtNote createNewNote(ZZCell c, double[] ncenter, + double[] ndim) { + AwtNote newNote = new AwtNote(); + newNote.setCell(c); + newNote.setCoord(ncenter[0], ncenter[1]); + newNote.setDimension(ndim[0], ndim[1]); + newNote.cellRepr(); + return newNote; + } + + public void deleteNote(ZZCell nc) { + // should delete ZOb structures ... in future + // ZObCellRepr will have 'deleteZOb' method. + ZZCell hc = nc.h(d_clone); + nc.delete(); + if(hc.getRankLength(d_clone)==1) { + hc.delete(); + } + } + + static public void createNewLink(ZZCell from, ZZCell to) { + ZZCell newLinkCell = from.h(AwtUtil.d_to, 1).N(AwtUtil.d_to, 1); + to.h(AwtUtil.d_from, -1).connect(AwtUtil.d_from, -1, newLinkCell); + AwtLink al = new AwtLink(); + al.setCell(newLinkCell); + al.cellRepr(); + } + + static public void renderGrid(FlobSet into, AwtMetrics M, double x1, double + y1, double x2, double y2, Color color, int density) + { + double[] coord = new double[2], cstart = new double[2], cinc = new double[2], + d = new double[2], dh = new double[2]; + Point p1, p2; + int i, j, a, b; + cstart[0] = (x1 < x2) ? x1 : x2; + cstart[1] = (y1 < y2) ? y1 : x2; + cinc[0] = Math.abs((x2-x1) / ((double)density + 1.0)); + cinc[1] = Math.abs((y2-y1) / ((double)density + 1.0)); + d[0] = cinc[0] / 5.0; + d[1] = cinc[1] / 5.0; + dh[0] = d[0]/2.0; + dh[1] = d[1]/2.0; + + for(a=0; a<2; a++) { + b = (a==0) ? 1 : 0; + coord[a] = cstart[a]; + for(i=0; i<=density+1; i++) { + coord[b] = cstart[b]+dh[b]/2.0; + for(j=1; j<=(density+1)*5; j++) { + p1 = M.mapToRealView(coord); + coord[b] += dh[b]; + p2 = M.mapToRealView(coord); + coord[b] += dh[b]; + into.add(new LineDecor(p1.x, p1.y, p2.x, p2.y, color, 2)); + } + coord[a] += cinc[a]; + } + } + } +} + + + + + + diff --git a/Modules/awtool/AwtView1.java b/Modules/awtool/AwtView1.java new file mode 100644 index 0000000..e3bf3be --- /dev/null +++ b/Modules/awtool/AwtView1.java @@ -0,0 +1,341 @@ +/* +AwtView1.zob + * + * Copyright (c) 2000-2001 Ted Nelson and Tuomas Lukka + * Copyright (c) 2000-2001 Kimmo Wideroos + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +/** View for a(ssociative) writing tool +*/ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; +//import java.lang.reflect.*; + +public class AwtView1 extends Awtool { + + static AwtNileView awtNile = new AwtNileView(); + + class AwtBgFlob extends CellBgFlob { + + public AwtBgFlob(int x, int y, int d, int w, int h, ZZCell c) { + super(x, y, d, w, h, c); + } + + public void render(Graphics g, int mx, int my, int md, int mw, int mh) { + + Color[] solids = getSolidColors(); + int nsolids = 0; + + if(solids!=null) nsolids = solids.length; + + Color oldfg = g.getColor(); + Shape oldclip = g.getClip(); + + g.clipRect(mx, my, mw, mh); + + if(solids != null) { + int iq=0, id=0; + for(int i=0; i0 && mh-iq-5>0) { + g.drawRect(mx+id+1, my+id+1, mw-iq-3, mh-iq-3); + g.drawRect(mx+id+2, my+id+2, mw-iq-5, mh-iq-5); + id += 2; + iq += 4; + } + g.setColor(bg); + g.fillRect(mx+id+1, my+id+1, mw-iq-3, mh-iq-3); + //g.fillRect(mx+(mw*i)/nsolids, my, mw/nsolids+1, mh); + } + } else { + g.setColor(bg); + g.fillRect(mx, my, mw, mh); + } + + g.setColor(oldfg); + + renderContent(g, mx, my, mw, mh); + + // XXX Span indication??? + + g.drawRect(mx, my, mw-1, mh-1); + + g.setClip(oldclip); + } + } + + class AwtLinkFlob extends CellBgFlob { + + Point from, to; + + AwtLinkFlob(Point from, Point to, ZZCell c) { + super((from.x+to.x)>>1, (from.y+to.y)>>1, Math.abs(from.x-to.x), + Math.abs(from.y-to.y), 2, c); + this.from = from; + this.to = to; + //super((from.x+to.x)>>1, (from.y+to.y)>>1, w, h, 2, c); + } + + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + + Color[] solids = getSolidColors(); + int nsolids = 0; + + if(solids!=null) nsolids = solids.length; + + Color oldfg = g.getColor(); + //Shape oldclip = g.getClip(); + + // XXX save font? + + //g.clipRect(mx, my, mw, mh); + + if(solids != null) { + int lx, ly, dw, dh; + lx = from.x; + ly = from.y; + dw = lx - to.x; + dh = ly - to.y; + for(int i=0; i= 0) + nileOn = true; + } + + Dimension nDim; + Point nCoord = new Point(); + Rectangle rect; + + // if note is dragged, draw only that one + if(Awtool.dragNote != null) { + nCoord = M.mapToRealView(dragNote.getX(), dragNote.getY()); + nDim = M.getRealDimension(dragNote.getX(), dragNote.getY(), dragNote.getDimension()); + rect = new Rectangle(nCoord.x-(nDim.width>>1), nCoord.y-(nDim.height>>1), + nDim.width, nDim.height); + makeAwtNote(into, view, dragNote.getCell(), rect, nileOn); + return; + } + + + + ZZCell activeCategory = + AwtUtil.getCursoredCell(Awtool.c_activeCategory, awtsyslist); + //view.getSpace().getCellByID("1051"); //getActiveCategory(view); + if(activeCategory==null) { + activeCategory = + awtsyslist.h(AwtUtil.d_categories,1). + s(AwtUtil.d_categories, -1). + getOrNewCell(AwtUtil.d_categories); + AwtUtil.setCursor(Awtool.c_activeCategory, activeCategory, awtsyslist); + } + Categories C = new Categories(activeCategory); + + AwtNote[] validNotes = C.getValidNotes(); + + // 'renderedNotes': key = notecell, value = {int x, y, w, h} + Hashtable renderedNotes = new Hashtable(); + + Vector notFixedNotes = new Vector(); + ZZCell noteCell, noteParams, categoryLinkCell; + AwtLink catlink; + AwtNote note; + int[] noteSize; + double y, x, yRowMax=0.0, w, h, gap=0.1; + + for(int i=0; i>1), nCoord.y-(nDim.height>>1), + nDim.width, nDim.height); + makeAwtNote(into, view, noteCell, rect, nileOn); + + } + + AwtUtil.quickSort(notFixedNotes, 0, notFixedNotes.size()-1, + new AwtUtil.ObjectComparator() { + public int compare(Object o1, Object o2) { + return (( ((AwtNote)o1).getHeight() < + ((AwtNote)o2).getHeight() ) ? 1 : 0 ); + } + }); + + y = 1.0-gap; x = gap; + for(Enumeration e=notFixedNotes.elements(); e.hasMoreElements();){ + note = (AwtNote)e.nextElement(); + noteCell = note.getCell(); + w = note.getWidth(); + if(x+w>1.0-gap) { + x = gap; + y += yRowMax; + yRowMax = 0; + } + h = note.getHeight(); + note.setCoord(x+(w/2.0), y+(h/2.0)); + x += (w+gap); + if(h>yRowMax) yRowMax = h; + + + nCoord = M.mapToRealView(note.getX(), note.getY()); + + nDim = M.getRealDimension(note.getX(), note.getY(), note.getDimension()); + + // importtant: notes' headcells as keys + renderedNotes.put(noteCell.h(AwtUtil.d_clone), + new int[] { nCoord.x, nCoord.y, nDim.width, nDim.height }); + + rect = new Rectangle(nCoord.x, nCoord.y, nDim.width, + nDim.height); + makeAwtNote(into, view, noteCell, rect, nileOn); + //fact.centerFlob(into, noteCell, noteCell, 1, + // nCoord, 0, 0, 1, nDim); + } + + // render links + + int[] toField, fromField; + ZZCell toc, fromc; + AwtLink al; + AwtLink[] validLinks = C.getAllValidLinks(true, true); + + for(int i=0; iDefault value:
     600;
    . + + * @structparam 1 + */ + + public + int viewWidth + = 600; + int viewHeight + = 600; + int viewX + = 100; + int viewY + = 100; + + + /* AUTOGENERATED! */ + static final private int fullmask = 1; + + /* AUTOGENERATED! */ + public String readParams(ZZCell start) { + int m = 0; + try { + if(start != null) + m = readParams(start, 0); + } catch(Throwable t) { + ZZLogger.exc(t); + } finally { + + } + if((m & fullmask) != fullmask) { + // not all parameters present - no problem right now. + } + return ""; + } + + /* AUTOGENERATED! */ + private int readParams(ZZCell start, int mask) { + ZZCell n = start; + while(n != null) { + String s = n.getText(); + // Tests autogenerated from members. + + if(s.equals("viewWidth")) { + mask |= 1; + try { + ZZCell c = n.s("d.1"); s = c.getText(); viewWidth = Integer.parseInt(s); + } catch(Exception e) { + ZZLogger.exc(e); + } + } else + + + { } // grab that last "else" + ZZCell h = n.h("d.3"); + if(h != null && h != n) { + // recurse + mask |= readParams(h, mask); + } + n = n.s("d.2"); + } + return mask; + } + + + + + + static boolean NileOn = false; + static AwtNote dragNote; + static Point dragOffs = new Point(0, 0); + static Point dragCoord = new Point(0, 0); + + static boolean creatingNote = false; + + static long focusChangedLastTime = -1; // millisecs + + static AwtCursor c_cursor1 = new AwtCursor(Color.red, true); + static AwtCursor c_cursor2 = new AwtCursor(Color.gray, true); + static AwtCursor c_activeCategory = new AwtCursor(Color.orange, false); + static AwtCursor c_metrics = new AwtCursor(Color.white, false); + + public boolean accept(Object o) { + if(!(o instanceof ZZCell)) return false; + return true; + } + + static public Hashtable categ; + static public Hashtable notes; + static public Hashtable validNotes; + + static class NotemapBM extends BooleanMesh { + public NotemapBM(ZZCell bStructure) { super(bStructure); } + public boolean testBelonging(ZZCell nhc, ZZCell category) { + for(ZZCell l=category.h(AwtUtil.d_clone).s(AwtUtil.d_to); l != null; l=l.s(AwtUtil.d_to) ) + if(l.h(AwtUtil.d_from,1).h(AwtUtil.d_clone).equals(nhc)) return true; + return false; + } + } + + + + /* categories are a kind of layers containing notes (i.e. (text) elements). + * this class provides with logical operations for categories (AND, OR). + * the resulting categories should be able to store permanently in zzspace. + * heavily under construction ... + */ + public class Categories extends ZObCellRepr { + private Hashtable AllNoteHeadCells = null; + private Hashtable AllNotes = null; + private Hashtable AllValidNotes = null; + private Hashtable ValidNotes = null; + private Hashtable K = new Hashtable(); + private NotemapBM bm; + private String categoryName = "SCRATCH"; + + public boolean isCategory(ZZCell c) { + return (c.h(AwtUtil.d_clone).getRankLength(AwtUtil.d_categories)>1); + } + + public Categories(ZZCell bStructure) { + setCell(bStructure); + _findCategories(bStructure); + bm = new NotemapBM(bStructure); + + AllNotes = new Hashtable(); + AllNoteHeadCells = new Hashtable(); + AllValidNotes = new Hashtable(); + ValidNotes = new Hashtable(); + + ZZCell note, chc, nhc; + for(Enumeration e = K.keys(); e.hasMoreElements(); ) { + // chc = category headcell + chc = ((ZZCell)e.nextElement()); + for(ZZCell linkc = chc.s(AwtUtil.d_to); linkc != null; + linkc = linkc.s(AwtUtil.d_to) ) + { + note = linkc.h(AwtUtil.d_from, 1); + nhc = note.h(AwtUtil.d_clone); + AllNotes.put(note, nhc); + if(!AllNoteHeadCells.containsKey(nhc)) + // AllNoteHeadCells must keep track of all note headcells + AllNoteHeadCells.put(nhc, note); + if(AllValidNotes.containsKey(nhc)) + // AllValidNotes store valid headcells AND clones + // all together + AllValidNotes.put(note, nhc); + else if(bm.evaluate(nhc)) AllValidNotes.put(note, nhc); + if(AllValidNotes.containsKey(note)) { + // If there exist 2 or more valid note clones, ValidNotes + // store note headcell (otherwise note clone). + if(ValidNotes.containsKey(nhc)) ValidNotes.put(nhc, nhc); + else ValidNotes.put(nhc, note); + } + } + } + } + + private void _findCategories(ZZCell bStructure) { + if(isCategory(bStructure)) { + K.put(bStructure.h(AwtUtil.d_clone), bStructure); + return; + } else + { + _findCategories(bStructure.s("d.1")); + _findCategories(bStructure.s("d.2")); + } + } + + public ZZCell[] getNoteCells() { + ZZCell[] n = new ZZCell[AllNotes.size()]; + Enumeration e = AllNotes.elements(); + int i = 0; + while (e.hasMoreElements()) { + n[i] = (ZZCell)e.nextElement(); i++; + } + return n; + } + public AwtNote[] getNotes() { + AwtNote[] n = new AwtNote[AllNotes.size()]; + Enumeration e = AllNotes.elements(); + ZZCell ncell; + int i = 0; + while (e.hasMoreElements()) { + ncell = (ZZCell)e.nextElement(); + n[i] = (AwtNote)AwtUtil.readZObClone(ncell); + n[i].setCell(ncell); + i++; + } + return n; + } + + public ZZCell[] getAllValidNoteCells() { + ZZCell[] ln = new ZZCell[AllValidNotes.size()]; + int i = 0; + for(Enumeration e=AllValidNotes.keys(); e.hasMoreElements();) { + ln[i] = (ZZCell)e.nextElement(); + i++; + } + return ln; + } + + public AwtNote[] getAllValidNotes() { + AwtNote[] ln = new AwtNote[AllValidNotes.size()]; + ZZCell ncell; + int i = 0; + for(Enumeration e=AllValidNotes.keys(); e.hasMoreElements();) { + ncell = (ZZCell)e.nextElement(); + ln[i] = (AwtNote)AwtUtil.readZObClone(ncell); + ln[i].setCell(ncell); + i++; + } + return ln; + } + + public ZZCell[] getValidNoteCells() { + ZZCell[] ln = new ZZCell[ValidNotes.size()]; + int i = 0; + for(Enumeration e=ValidNotes.elements(); e.hasMoreElements(); ) { + ln[i] = (ZZCell)e.nextElement(); + i++; + } + return ln; + } + + public AwtNote[] getValidNotes() { + AwtNote[] ln = new AwtNote[ValidNotes.size()]; + ZZCell ncell; + int i = 0; + for(Enumeration e=ValidNotes.elements(); e.hasMoreElements(); ) { + ncell = (ZZCell)e.nextElement(); + ln[i] = (AwtNote)AwtUtil.readZObClone(ncell); + ln[i].setCell(ncell); + i++; + } + return ln; + } + + public ZZCell[] getK() { + ZZCell[] cat = new ZZCell[K.size()]; + Enumeration e = K.elements(); + int i = 0; + while (e.hasMoreElements()) + cat[i] = (ZZCell)e.nextElement(); i++; + return cat; + } + + public ZZCell[] getAllValidLinkCells(boolean internal, boolean external) { + return _getvalidlinks(internal, external, AllValidNotes.keys()); + } + + public AwtLink[] getAllValidLinks(boolean internal, boolean external) + { + ZZCell[] linkcells = _getvalidlinks(internal, external, AllValidNotes.keys()); + AwtLink[] links = new AwtLink[linkcells.length]; + for(int i = 0; i=0; i--) { + note = validNotes[i]; + catlink.setX(note.getX()); catlink.setY(note.getY()); + catlink.cellRepr(catCell, false); + // note's centralcell is a clone of its (ZOb's) original + // central cell; that's why '...im2), true);' + note.cellRepr(catCell.getOrNewCell(AwtUtil.d_from), true); + catCell = catCell.getOrNewCell(AwtUtil.d_to); + } + return ""; + } + } + + /** return note cell, if possible + */ + static ZZCell getNoteCellOrCursor(Object ob) { + ZZCell c = null; + if(ob instanceof ZZCursor) c = ((ZZCursor)ob).get(); + else if(ob instanceof ZZCell) c = (ZZCell)ob; + else return null; + ZZCell link = c.s(AwtUtil.d_from, -1); + if(link == null) return null; + if(link.s(AwtUtil.d_to, -1) == null) return null; + return c; + } + + static public void nile_action(String id, ZZCell vc1, ZZCell vc2, String key, + ZZCursor cur) { + + boolean split = false; + + ZZCell viewCell = vc1; + ZZCell otherCell = vc2; + + p("Nile action: id: '"+id+"' key: '"+key); + + StringTokenizer st = new StringTokenizer(id); + String[] toks = new String[st.countTokens()]; + for(int i=0; i 1) { + if(toks[1].equals("+")) dir = 1; + else if(toks[1].equals("-")) dir = -1; + + if(toks.length > 2) { + if(toks[2].equals("CHAR")) + unit = new Nile2Unit.Char(); + else if(toks[2].equals("WORD")) + unit = new Nile2Unit.Word(); + else if(toks[2].equals("SENT")) + unit = new Nile2Unit.Sentence(); + else if(toks[2].equals("PARA")) + unit = new Nile2Unit.Paragraph(); + } + } + + id = toks[0]; + + if(id.equals("Cursor")) { + p("Cursor: "+dir); + Nile2Ops.moveCursor(unit, viewCell, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("AdjLeft")) { + Nile2Ops.adjust(unit, viewCell, -1, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("AdjRight")) { + Nile2Ops.adjust(unit, viewCell, 1, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("Hop")) { + Nile2Ops.hop(unit, viewCell, dir); + } + else if(id.equals("Mode")) { + Nile2Ops.setCursor(unit, viewCell, null); + if(split) + Nile2Ops.setCursor(unit, otherCell, null); + } + else if(id.equals("Insert")) { + Nile2Ops.insert(viewCell, key); + + // Set the selection of other half to char mode, too + if(split) + Nile2Ops.setCursor(new Nile2Unit.Char(), otherCell, null); + } + else if(id.equals("BackSpace")) { + Nile2Ops.backspace(unit, viewCell); + } + else if(id.equals("Delete")) { + Nile2Ops.del(unit, viewCell); + } + else if(id.equals("BreakParagraph")) { + Nile2Ops.breakParagraph(unit, viewCell); + } + else if(id.equals("Tunnel")) { + if(otherCell != null) { + Nile2Ops.tunnel(unit, otherCell, viewCell, dir, false); + } + } + else if(id.equals("Transcopy")) { + if(otherCell != null) { + Nile2Ops.tunnel(unit, otherCell, viewCell, dir, true); + } + } + else if(id.equals("PUICopy")) { + ZZCell c = ZZCursorReal.get(viewCell); + String s = Nile2Ops.stringify(c); + ZZUtil.puiCopy(s); + } + /* + else if(id.equals("TraverseTranscopies")) { + Nile2Ops.traverseTranscopies(viewCell, dir); + } + */ + + //Object ob = null; + //if(pt != null) + // ob = xi.getObjectAt(pt.x, pt.y); + + if(id.equals("MouseSetCursor") && cur!=null) { + p("Setting cursor from mouse! Unit: "+unit); + if(cur.get().h("d.nile").equals(viewCell)) { + Nile2Ops.setCursor(unit, viewCell, cur); + } else + if(cur.get().h("d.nile").equals(otherCell)) { + Nile2Ops.setCursor(unit, otherCell, cur); + } + } + } + + + abstract public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed); + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + + ZZUpdateManager.setFast(view); + Object ob = null; + AwtNote note = null; + AwtMetrics M; + ZZCell nc; + Point noteRVCoord = null; + double[] noteVVCoord = null; + double deltaX, deltaY; + + if(pt != null && xi != null) ob = xi.getObjectAt(pt.x, pt.y); + + nc = getNoteCellOrCursor(ob); + + if(nc != null) { + note = (AwtNote)AwtUtil.readZObClone(nc); + note.setCell(nc); + } + + boolean forceOrigoChange = false; + ZZCell AwtSystemList; + ZZCell vc = view.getViewcell(); + + pa("NOTECELL: "+nc); + + pa("Note action! '"+id+"' key: "+key); + + // is nile mode on? + boolean nileOn = false; + ZZCell curb = vc.h("d.bind", 1, true); + if(curb!=null) { + String mode = ZZCursorReal.get(curb).getText(); + if(mode.indexOf("Nile") >= 0) + nileOn = true; + } + pa("OBJECT: "+ob); + boolean isC = false; + if(ob instanceof ZZCursor) isC = true; + pa("IS CURSOR?: "+isC); + // if we have object which is not cursor, then nile action is impossible + if(nileOn && !(!(ob instanceof ZZCursor) && (ob != null)) ) { + ZZCell nvc1 = AwtUtil.getCursoredCell(c_cursor1, vc); + ZZCell nvc2 = AwtUtil.getCursoredCell(c_cursor2, vc); + if(nvc1==null) return; + + if(nvc1.s("d.cursor-cargo", -1)==null) { + ZZCursorReal.set(nvc1, nvc1); + ZZCursorReal.setOffs(nvc1, 0); + } + if(nvc2!=null) + if(nvc2.s("d.cursor-cargo", -1)==null) { + ZZCursorReal.set(nvc2, nvc2); + ZZCursorReal.setOffs(nvc2, 0); + } + + nile_action(id, nvc1, nvc2, key, (ZZCursor)ob); + //Nile1.module.action(id,code,target,nview,cview,key,pt,xi); + return; + } + + if(id.equals("TESTWIN")) { + AwtSystemList = target; + + // set awt dims + AwtUtil.addDims(ZZDefaultSpace.findDefaultDimlist(code.getHomeCell())); + + // Cursors + ZZCell curs = AwtSystemList.findText(AwtUtil.d_awtool, 1, "Cursors"); + if(curs == null) { + ZZCell nCurs1, nCurs2, cat1; + ZZCell cursors = AwtSystemList.N(AwtUtil.d_awtool); + cursors.setText("Cursors"); + cursors.N("d.1"); + } + + // View + ZZCell rastname, rl, rc = AwtSystemList.findText(AwtUtil.d_awtool, 1, "View"); + if(rc == null) { + rc = AwtSystemList.N(AwtUtil.d_awtool); + rc.setText("View"); + rl = rc.N("d.1"); + rl.connect("d.2", 1, rl); + rl.setText("Awtool"); + rastname = rl.N("d.1"); + rastname.setText("Awtool.View1"); + } else { + rl = rc.s("d.1"); + rastname = rl.s("d.1"); + } + + + // Bindings + ZZCell bindhome = AwtSystemList.findText(AwtUtil.d_awtool, 1, "Bind"); + if(bindhome == null) { + bindhome = AwtSystemList.N(AwtUtil.d_awtool); + bindhome.setText("Bind"); + bindhome = bindhome.N("d.1", 1); + + //ZZDefaultSpace.mkCorner(bindhome, actions); + actions(bindhome.h("d.2", 1)); + } else { + bindhome = bindhome.s("d.1"); + } + // View metrics + ZZCell metr = AwtSystemList.findText(AwtUtil.d_awtool, 1, "Metrics"); + if(metr == null) { + Dimension RV = new Dimension(400, 400); + Dimension VV = new Dimension(1000, 1000); + // create 'metrics collection' + metr = AwtSystemList.N(AwtUtil.d_awtool); + metr.setText("Metrics"); + ZZCell mnew, metrList; + + mnew = metrList = metr.N("d.1"); + + M = new AwtMetricsNormal(mnew, RV, VV, 0.0,0.0); + M.cellRepr(); + + mnew = mnew.N("d.2"); + M = new AwtMetricsFC(mnew, RV, VV, 0.0, 0.0); + M.cellRepr(); + + mnew = mnew.N("d.2"); + M = new AwtMetricsFC2(mnew, RV, VV, 0.0, 0.0); + M.cellRepr(); + + // make circle + mnew.connect("d.2", 1, metrList); + AwtUtil.setCursor(c_metrics, metrList, AwtSystemList); + + + } else { + ZZCell currentMetrics = + AwtUtil.getCursoredCell(c_metrics, AwtSystemList); + if(currentMetrics == null) { + currentMetrics = metr.s("d.1"); + AwtUtil.setCursor(c_metrics, currentMetrics, AwtSystemList); + } + M = (AwtMetrics)AwtUtil.readZObClone(currentMetrics); + M.setCell(currentMetrics); + } + + // searching for active category ... + ZZCell ac = AwtUtil.getCursoredCell(c_activeCategory, AwtSystemList); + if(ac == null) { + if(AwtSystemList.getRankLength(AwtUtil.d_categories)>1) { + ac = AwtSystemList.s(AwtUtil.d_categories); + } else { + ac = AwtSystemList.N(AwtUtil.d_categories); + ac.setText("* SCRATCH *"); + } + AwtUtil.setCursor(c_activeCategory, ac, AwtSystemList); + } + + ZZCell v = ZZDefaultSpace.newToplevelView(rc.getSpace(), + "awtool", 0, 0, M.RealView[0], M.RealView[1], + rl, null, + null, null, + null, + new Color(0xFFFFB1)); + + // Then, set bindings + ZZCell bcurs = v.getOrNewCell("d.bind", 1); + ZZCursorReal.set(bcurs, bindhome); + ZZCursorReal.setColor(bcurs, Color.black); + + + ZZCell awtc = v.h("d.2", 1).N("d.2"); + awtc.setText("AwtSystemList"); + ZZCursorReal.set(awtc, AwtSystemList); + // init shared cursors + ZZCell scursors = v.h("d.2",1).N("d.2"); + scursors.setText("SharedCursors"); + scursors.N("d.1"); + + return; + } + + AwtSystemList = AwtUtil.getAwtSysList(view.getViewcell()); + if(AwtSystemList == null && !id.equals("TESTWIN")) { + throw new ZZError("Awtool: AwtSystemList missing!!"); + } + + M = AwtUtil.getAwtMetrics(AwtSystemList); + + if(id.equals("StartDrag")) { + if(note != null) { + dragNote = note; + noteRVCoord = M.mapToRealView(note.getX(), note.getY()); + dragOffs.x = noteRVCoord.x - pt.x; + dragOffs.y = noteRVCoord.y - pt.y; + } + } else + + if(id.equals("StopDrag") && dragNote != null) { + noteVVCoord = M.mapToVirtualView(pt.x + dragOffs.x, pt.y + dragOffs.y); + dragNote.setCoord(noteVVCoord[0], noteVVCoord[1]); + dragNote.cellRepr(); + dragOffs.x = 0; dragOffs.y = 0; + dragNote = null; + } else + + if(id.equals("Dragged") && dragNote != null) { + noteVVCoord = M.mapToVirtualView(pt.x + dragOffs.x, pt.y + dragOffs.y); + dragNote.setCoord(noteVVCoord[0], noteVVCoord[1]); + ZZUpdateManager.chg(); + //dragNote.cellRepr(); + } else + + + if(id.equals("StartResize")) { + if(note != null) { + dragNote = note; + noteRVCoord = M.mapToRealView(note.getX(), note.getY()); + dragOffs.x = noteRVCoord.x - pt.x; + dragOffs.y = noteRVCoord.y - pt.y; + } + } else + + if(id.equals("StopResize") && dragNote != null) { + noteVVCoord = M.mapToVirtualView(pt.x + dragOffs.x, pt.y + dragOffs.y); + dragNote.setCoord(noteVVCoord[0], noteVVCoord[1]); + dragNote.cellRepr(); + dragOffs.x = 0; dragOffs.y = 0; + dragNote = null; + } else + + if(id.equals("Resizing") && dragNote != null) { + } else + + if(id.equals("StartCreatingNote")) { + dragCoord = pt; + // this is chanced to 'true' when dragging occurs + creatingNote = false; + } else + + if(id.equals("CreatingNote")) { + creatingNote = true; + } else + + if(id.equals("StopCreatingNote") && creatingNote) { + ZZCell newNoteCell; + AwtNote newNote; + int cx = (dragCoord.x+pt.x)>>1; + int cy = (dragCoord.y+pt.y)>>1; + double[] ndim, nvcenter = M.mapToVirtualView(cx, cy); + Dimension nd = new Dimension(Math.abs(dragCoord.x-pt.x), Math.abs(dragCoord.y-pt.y)); + ndim = M.getVirtualDimension(cx, cy, nd); + + ZZCell ac = AwtUtil.getCursoredCell(c_activeCategory, vc); + + ZZCell noteCell = + ac.h(AwtUtil.d_to).N(AwtUtil.d_to).N(AwtUtil.d_from); + + AwtUtil.createNewNote(noteCell, nvcenter, ndim); + // attach new note also to 'notes' dimension along + // active category cell. + ac.h(AwtUtil.d_notes, 1).connect(AwtUtil.d_notes, 1, noteCell); + dragCoord.x = 0; + dragCoord.y = 0; + creatingNote = false; + + } else + + if(id.equals("SetCursor1") && nc != null) { + ZZCell red = AwtUtil.getCursoredCell(c_cursor1, vc); + if(red.equals(nc)) return; + AwtUtil.setCursor(c_cursor2, red, vc); + AwtUtil.setCursor(c_cursor1, nc, vc); + if(red!=null) { + red.excise("d.nile-wins"); + nc.connect("d.nile-wins", 1, red); + nc.connect("d.nile-wins", -1, red); + } + } else + + if(id.equals("SetCursor2") && nc != null) { + ZZCell gray = AwtUtil.getCursoredCell(c_cursor2, vc); + if(gray.equals(nc)) return; + AwtUtil.setCursor(c_cursor1, gray, vc); + AwtUtil.setCursor(c_cursor2, nc, vc); + if(gray!=null) { + gray.excise("d.nile-wins"); + nc.connect("d.nile-wins", 1, gray); + nc.connect("d.nile-wins", -1, gray); + } + + } else + + if(id.equals("NewLink")) { + ZZCell c1, c2; + c1 = AwtUtil.getCursoredCell(c_cursor1, vc); + c2 = AwtUtil.getCursoredCell(c_cursor2, vc); + if(c1 != null && c2 != null && c1 != c2) { + AwtUtil.createNewLink(c1, c2); + } + } else + + if(id.equals("ChangeMetrics")) { + // save current metrics (focus, origo, etc.) + M.cellRepr(); + ZZCell mc = AwtUtil.getCursoredCell(c_metrics, vc); + mc = mc.s("d.2"); + AwtUtil.setCursor(c_metrics, mc, vc); + M = (AwtMetrics)AwtUtil.readZObClone(mc); + M.setCell(mc); + ZZUpdateManager.chg(); + } else + + if(id.equals("ResetOrigo")) { + //pa("ORIGO RESET!"); + M.setOrigo(0.0, 0.0); + ZZUpdateManager.chg(); + } else + + if(id.equals("GridOnOff")) { + //pa("GRID ON/OFF!"); + boolean gon = M.GridOn; + M.GridOn = gon ? false : true; + if(M.GridOn != gon) { + M.cellRepr(); + } + ZZUpdateManager.chg(); + } else + + if(id.equals("FocusOrigoAndSelect")) { + long elapsedTime = Long.MAX_VALUE; + long cur = System.currentTimeMillis(); + double[] vf1, vf2; + + vf1 = M.mapToVirtualView(pt.x, pt.y); + M.setFocusOrigo(pt.x, pt.y, nc); + vf2 = M.mapToVirtualView(pt.x, pt.y); + M.moveOrigo(vf1[0]-vf2[0], vf1[1]-vf2[1]); + M.cellRepr(); + + if(focusChangedLastTime > 0) { + elapsedTime = cur - focusChangedLastTime; + focusChangedLastTime = -1; + } else { + focusChangedLastTime = cur; + } + + pa("ELAPSED_TIME: "+elapsedTime); + + if(elapsedTime < 1500) { + // 'doubleclick'-focus should change also origo + // this does not work reasonably + // forceOrigoChange = true; + forceOrigoChange = false; + } else { ZZUpdateManager.chg(); } + } + + + if(id.equals("ChangeOrigo") || forceOrigoChange) { + double[] vvp = M.mapToVirtualView(pt.x, pt.y); + // new origo is wanted to be in the center of realview + double[] realOrigo = M.mapToVirtualView(M.RealView[0]>>1, + M.RealView[1]>>1); + M.moveOrigo(vvp[0]-realOrigo[0], vvp[1]-realOrigo[1]); + M.cellRepr(); + ZZUpdateManager.chg(); + } + } + + public ZOb newZOb(String id) { + if(id.equals("View1")) + return new AwtView1(); + else + return null; + } + }; + + // This is really hacky part... + static ZZCell curAct; + static void a(String key, String act) { a(key, act, null); } + static void a(String key, String act, ZZCell next) { + curAct = curAct.N("d.2", 1); + curAct.setText(key); + ZZCell n = curAct.N("d.1", 1); + n.setText("Awtool." + act); + if(next != null) + next.insert("d.3", 1, n); + } + + static void actions(ZZCell start) { + ZZCell awtact = start; awtact.setText("Awtool mode"); + ZZCell nchar = awtact.N("d.1",1); nchar.setText("Nile char"); + ZZCell nword = nchar.N("d.1", 1); nword.setText("Nile word"); + ZZCell nsent = nword.N("d.1", 1); nsent.setText("Nile sent"); + ZZCell npara = nsent.N("d.1", 1); npara.setText("Nile para"); + + ZZCell ncommon = npara.N("d.1", 1); ncommon.setText("Nile common"); + + + + curAct = nword; + // Annoying - these should be structurally + // describable!!! + a("MouseClicked1", "MouseSetCursor 0 WORD"); + a("Backspace", "BackSpace 0 WORD"); + a("Delete", "Delete 0 WORD"); + a("Alt-Backspace", "Delete 0 WORD"); + a("Ctrl-P", "Tunnel - WORD"); // P for pull + a("Ctrl-T", "Transcopy - WORD"); + a("Left", "Cursor - WORD"); + a("Right", "Cursor + WORD"); + a("Shift-Left", "AdjLeft - WORD"); + a("Shift-Right", "AdjRight + WORD"); + a("Ctrl-Left", "AdjRight - WORD"); + a("Ctrl-Right", "AdjLeft + WORD"); + a("Alt-Left", "Hop - WORD"); + a("Alt-Right", "Hop + WORD"); + a("Enter", "BreakParagraph 0 WORD"); + + a("Up", "Cursor - SENT"); + a("Down", "Cursor + SENT"); + a("Alt-Up", "Hop - SENT"); + a("Alt-Down", "Hop + SENT"); + + a("INSERT", "Insert", nchar); + a("Tab", "Mode 0 SENT", nsent); + // awtool specific + a("Alt-N", "NileOnOff", awtact); + + curAct = nsent; + a("MouseClicked1", "MouseSetCursor 0 SENT"); + a("Backspace", "BackSpace 0 SENT"); + a("Delete", "Delete 0 SENT"); + a("Alt-Backspace", "Delete 0 SENT"); + a("Ctrl-P", "Tunnel - SENT"); // P for push + a("Ctrl-T", "Transcopy - SENT"); + a("Left", "Cursor - SENT"); + a("Right", "Cursor + SENT"); + a("Shift-Left", "AdjLeft - SENT"); + a("Shift-Right", "AdjRight + SENT"); + a("Ctrl-Left", "AdjRight - SENT"); + a("Ctrl-Right", "AdjLeft + SENT"); + a("Alt-Left", "Hop - SENT"); + a("Alt-Right", "Hop + SENT"); + a("Enter", "BreakParagraph 0 SENT"); + + a("Up", "Cursor - PARA"); + a("Down", "Cursor + PARA"); + a("Alt-Up", "Hop - PARA"); + a("Alt-Down", "Hop + PARA"); + + a("INSERT", "Insert", nchar); + a("Tab", "Mode 0 CHAR", nchar); + // awtool specific + a("Alt-N", "NileOnOff", awtact); + +/* + curAct = npara; + a("MouseClicked1", "MouseSetCursor 0 PARA"); + a("Backspace", "BackSpace 0 PARA"); + a("Delete", "Delete 0 PARA"); + a("Alt-Backspace", "Delete 0 PARA"); + a("Left", "Cursor - PARA"); + a("Right", "Cursor + PARA"); + a("Shift-Left", "AdjLeft - PARA"); + a("Shift-Right", "AdjRight + PARA"); + a("Ctrl-Left", "AdjRight - PARA"); + a("Ctrl-Right", "AdjLeft + PARA"); + a("Alt-Left", "Hop - PARA"); + a("Alt-Right", "Hop + PARA"); + + a("INSERT", "Insert"); + a("Tab", "Mode 0 CHAR", nchar); + */ + + curAct = nchar; + a("MouseClicked1", "MouseSetCursor 0 CHAR"); + a("Left", "Cursor - CHAR"); + a("Right", "Cursor + CHAR"); + a("Backspace", "BackSpace 0 CHAR"); + a("Delete", "Delete 0 CHAR"); + a("Alt-Backspace", "Delete 0 CHAR"); + a("INSERT", "Insert"); + a("Tab", "Mode 0 WORD", nword); + a("Enter", "BreakParagraph 0 CHAR"); + + a("Ctrl-C", "PUICopy 0 CHAR"); + + a("Up", "Cursor - WORD"); + a("Down", "Cursor + WORD"); + // awtool specific + a("Alt-N", "NileOnOff", awtact); + + // awtool acts + curAct = awtact; + a("MouseStartDrag", "StartDrag"); + a("MouseDragged1", "Dragged"); + a("MouseReleased1", "StopDrag"); + a("Shift-MouseStartDrag", "StartCreatingNote"); + a("Shift-MouseDragged1", "CreatingNote"); + a("Shift-MouseReleased1", "StopCreatingNote"); + a("Shift-MouseClicked3", "ChangeOrigo"); + a("MouseClicked3", "FocusOrigoAndSelect"); + a("Shift-MouseClicked1", "SetCursor2"); + a("MouseClicked1", "SetCursor1"); + a("l", "NewLink"); + a("m", "ChangeMetrics"); + a("g", "GridOnOff"); + a("r", "ResetOrigo"); + a("Alt-N", "NileOnOff", nchar); + + } +} diff --git a/Modules/awtool/Awtool.zob b/Modules/awtool/Awtool.zob new file mode 100644 index 0000000..a6dca86 --- /dev/null +++ b/Modules/awtool/Awtool.zob @@ -0,0 +1,955 @@ +/* +Awtool.zob + * + * Copyright (c) 2000-2001 Ted Nelson and Tuomas Lukka + * Copyright (c) 2000-2001 Kimmo Wideroos + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos (inspired by Benjamin Fallenstein's notemap module) + */ + +/** Awt = A(ssociative) writing tool -demo +*/ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +public abstract class Awtool implements FlobView, FlobSet.DragCursor, ZOb { +public static final String rcsid = ""; + public static boolean dbg = true; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + /** View dimension (not in use now...) */ + int viewWidth + = 600; + int viewHeight + = 600; + int viewX + = 100; + int viewY + = 100; + } + + + + static boolean NileOn = false; + static AwtNote dragNote; + static Point dragOffs = new Point(0, 0); + static Point dragCoord = new Point(0, 0); + + static boolean creatingNote = false; + + static long focusChangedLastTime = -1; // millisecs + + static AwtCursor c_cursor1 = new AwtCursor(Color.red, true); + static AwtCursor c_cursor2 = new AwtCursor(Color.gray, true); + static AwtCursor c_activeCategory = new AwtCursor(Color.orange, false); + static AwtCursor c_metrics = new AwtCursor(Color.white, false); + + public boolean accept(Object o) { + if(!(o instanceof ZZCell)) return false; + return true; + } + + static public Hashtable categ; + static public Hashtable notes; + static public Hashtable validNotes; + + static class NotemapBM extends BooleanMesh { + public NotemapBM(ZZCell bStructure) { super(bStructure); } + public boolean testBelonging(ZZCell nhc, ZZCell category) { + for(ZZCell l=category.h(AwtUtil.d_clone).s(AwtUtil.d_to); l != null; l=l.s(AwtUtil.d_to) ) + if(l.h(AwtUtil.d_from,1).h(AwtUtil.d_clone).equals(nhc)) return true; + return false; + } + } + + + + /* categories are a kind of layers containing notes (i.e. (text) elements). + * this class provides with logical operations for categories (AND, OR). + * the resulting categories should be able to store permanently in zzspace. + * heavily under construction ... + */ + public class Categories extends ZObCellRepr { + private Hashtable AllNoteHeadCells = null; + private Hashtable AllNotes = null; + private Hashtable AllValidNotes = null; + private Hashtable ValidNotes = null; + private Hashtable K = new Hashtable(); + private NotemapBM bm; + private String categoryName = "SCRATCH"; + + public boolean isCategory(ZZCell c) { + return (c.h(AwtUtil.d_clone).getRankLength(AwtUtil.d_categories)>1); + } + + public Categories(ZZCell bStructure) { + setCell(bStructure); + _findCategories(bStructure); + bm = new NotemapBM(bStructure); + + AllNotes = new Hashtable(); + AllNoteHeadCells = new Hashtable(); + AllValidNotes = new Hashtable(); + ValidNotes = new Hashtable(); + + ZZCell note, chc, nhc; + for(Enumeration e = K.keys(); e.hasMoreElements(); ) { + // chc = category headcell + chc = ((ZZCell)e.nextElement()); + for(ZZCell linkc = chc.s(AwtUtil.d_to); linkc != null; + linkc = linkc.s(AwtUtil.d_to) ) + { + note = linkc.h(AwtUtil.d_from, 1); + nhc = note.h(AwtUtil.d_clone); + AllNotes.put(note, nhc); + if(!AllNoteHeadCells.containsKey(nhc)) + // AllNoteHeadCells must keep track of all note headcells + AllNoteHeadCells.put(nhc, note); + if(AllValidNotes.containsKey(nhc)) + // AllValidNotes store valid headcells AND clones + // all together + AllValidNotes.put(note, nhc); + else if(bm.evaluate(nhc)) AllValidNotes.put(note, nhc); + if(AllValidNotes.containsKey(note)) { + // If there exist 2 or more valid note clones, ValidNotes + // store note headcell (otherwise note clone). + if(ValidNotes.containsKey(nhc)) ValidNotes.put(nhc, nhc); + else ValidNotes.put(nhc, note); + } + } + } + } + + private void _findCategories(ZZCell bStructure) { + if(isCategory(bStructure)) { + K.put(bStructure.h(AwtUtil.d_clone), bStructure); + return; + } else + { + _findCategories(bStructure.s("d.1")); + _findCategories(bStructure.s("d.2")); + } + } + + public ZZCell[] getNoteCells() { + ZZCell[] n = new ZZCell[AllNotes.size()]; + Enumeration e = AllNotes.elements(); + int i = 0; + while (e.hasMoreElements()) { + n[i] = (ZZCell)e.nextElement(); i++; + } + return n; + } + public AwtNote[] getNotes() { + AwtNote[] n = new AwtNote[AllNotes.size()]; + Enumeration e = AllNotes.elements(); + ZZCell ncell; + int i = 0; + while (e.hasMoreElements()) { + ncell = (ZZCell)e.nextElement(); + n[i] = (AwtNote)AwtUtil.readZObClone(ncell); + n[i].setCell(ncell); + i++; + } + return n; + } + + public ZZCell[] getAllValidNoteCells() { + ZZCell[] ln = new ZZCell[AllValidNotes.size()]; + int i = 0; + for(Enumeration e=AllValidNotes.keys(); e.hasMoreElements();) { + ln[i] = (ZZCell)e.nextElement(); + i++; + } + return ln; + } + + public AwtNote[] getAllValidNotes() { + AwtNote[] ln = new AwtNote[AllValidNotes.size()]; + ZZCell ncell; + int i = 0; + for(Enumeration e=AllValidNotes.keys(); e.hasMoreElements();) { + ncell = (ZZCell)e.nextElement(); + ln[i] = (AwtNote)AwtUtil.readZObClone(ncell); + ln[i].setCell(ncell); + i++; + } + return ln; + } + + public ZZCell[] getValidNoteCells() { + ZZCell[] ln = new ZZCell[ValidNotes.size()]; + int i = 0; + for(Enumeration e=ValidNotes.elements(); e.hasMoreElements(); ) { + ln[i] = (ZZCell)e.nextElement(); + i++; + } + return ln; + } + + public AwtNote[] getValidNotes() { + AwtNote[] ln = new AwtNote[ValidNotes.size()]; + ZZCell ncell; + int i = 0; + for(Enumeration e=ValidNotes.elements(); e.hasMoreElements(); ) { + ncell = (ZZCell)e.nextElement(); + ln[i] = (AwtNote)AwtUtil.readZObClone(ncell); + ln[i].setCell(ncell); + i++; + } + return ln; + } + + public ZZCell[] getK() { + ZZCell[] cat = new ZZCell[K.size()]; + Enumeration e = K.elements(); + int i = 0; + while (e.hasMoreElements()) + cat[i] = (ZZCell)e.nextElement(); i++; + return cat; + } + + public ZZCell[] getAllValidLinkCells(boolean internal, boolean external) { + return _getvalidlinks(internal, external, AllValidNotes.keys()); + } + + public AwtLink[] getAllValidLinks(boolean internal, boolean external) + { + ZZCell[] linkcells = _getvalidlinks(internal, external, AllValidNotes.keys()); + AwtLink[] links = new AwtLink[linkcells.length]; + for(int i = 0; i=0; i--) { + note = validNotes[i]; + catlink.setX(note.getX()); catlink.setY(note.getY()); + catlink.cellRepr(catCell, false); + // note's centralcell is a clone of its (ZOb's) original + // central cell; that's why '...im2), true);' + note.cellRepr(catCell.getOrNewCell(AwtUtil.d_from), true); + catCell = catCell.getOrNewCell(AwtUtil.d_to); + } + return ""; + } + } + + /** return note cell, if possible + */ + static ZZCell getNoteCellOrCursor(Object ob) { + ZZCell c = null; + if(ob instanceof ZZCursor) c = ((ZZCursor)ob).get(); + else if(ob instanceof ZZCell) c = (ZZCell)ob; + else return null; + ZZCell link = c.s(AwtUtil.d_from, -1); + if(link == null) return null; + if(link.s(AwtUtil.d_to, -1) == null) return null; + return c; + } + + static public void nile_action(String id, ZZCell vc1, ZZCell vc2, String key, + ZZCursor cur) { + + boolean split = false; + + ZZCell viewCell = vc1; + ZZCell otherCell = vc2; + + p("Nile action: id: '"+id+"' key: '"+key); + + StringTokenizer st = new StringTokenizer(id); + String[] toks = new String[st.countTokens()]; + for(int i=0; i 1) { + if(toks[1].equals("+")) dir = 1; + else if(toks[1].equals("-")) dir = -1; + + if(toks.length > 2) { + if(toks[2].equals("CHAR")) + unit = new Nile2Unit.Char(); + else if(toks[2].equals("WORD")) + unit = new Nile2Unit.Word(); + else if(toks[2].equals("SENT")) + unit = new Nile2Unit.Sentence(); + else if(toks[2].equals("PARA")) + unit = new Nile2Unit.Paragraph(); + } + } + + id = toks[0]; + + if(id.equals("Cursor")) { + p("Cursor: "+dir); + Nile2Ops.moveCursor(unit, viewCell, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("AdjLeft")) { + Nile2Ops.adjust(unit, viewCell, -1, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("AdjRight")) { + Nile2Ops.adjust(unit, viewCell, 1, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("Hop")) { + Nile2Ops.hop(unit, viewCell, dir); + } + else if(id.equals("Mode")) { + Nile2Ops.setCursor(unit, viewCell, null); + if(split) + Nile2Ops.setCursor(unit, otherCell, null); + } + else if(id.equals("Insert")) { + Nile2Ops.insert(viewCell, key); + + // Set the selection of other half to char mode, too + if(split) + Nile2Ops.setCursor(new Nile2Unit.Char(), otherCell, null); + } + else if(id.equals("BackSpace")) { + Nile2Ops.backspace(unit, viewCell); + } + else if(id.equals("Delete")) { + Nile2Ops.del(unit, viewCell); + } + else if(id.equals("BreakParagraph")) { + Nile2Ops.breakParagraph(unit, viewCell); + } + else if(id.equals("Tunnel")) { + if(otherCell != null) { + Nile2Ops.tunnel(unit, otherCell, viewCell, dir, false); + } + } + else if(id.equals("Transcopy")) { + if(otherCell != null) { + Nile2Ops.tunnel(unit, otherCell, viewCell, dir, true); + } + } + else if(id.equals("PUICopy")) { + ZZCell c = ZZCursorReal.get(viewCell); + String s = Nile2Ops.stringify(c); + ZZUtil.puiCopy(s); + } + /* + else if(id.equals("TraverseTranscopies")) { + Nile2Ops.traverseTranscopies(viewCell, dir); + } + */ + + //Object ob = null; + //if(pt != null) + // ob = xi.getObjectAt(pt.x, pt.y); + + if(id.equals("MouseSetCursor") && cur!=null) { + p("Setting cursor from mouse! Unit: "+unit); + if(cur.get().h("d.nile").equals(viewCell)) { + Nile2Ops.setCursor(unit, viewCell, cur); + } else + if(cur.get().h("d.nile").equals(otherCell)) { + Nile2Ops.setCursor(unit, otherCell, cur); + } + } + } + + + abstract public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed); + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + + ZZUpdateManager.setFast(view); + Object ob = null; + AwtNote note = null; + AwtMetrics M; + ZZCell nc; + Point noteRVCoord = null; + double[] noteVVCoord = null; + double deltaX, deltaY; + + if(pt != null && xi != null) ob = xi.getObjectAt(pt.x, pt.y); + + nc = getNoteCellOrCursor(ob); + + if(nc != null) { + note = (AwtNote)AwtUtil.readZObClone(nc); + note.setCell(nc); + } + + boolean forceOrigoChange = false; + ZZCell AwtSystemList; + ZZCell vc = view.getViewcell(); + + pa("NOTECELL: "+nc); + + pa("Note action! '"+id+"' key: "+key); + + // is nile mode on? + boolean nileOn = false; + ZZCell curb = vc.h("d.bind", 1, true); + if(curb!=null) { + String mode = ZZCursorReal.get(curb).getText(); + if(mode.indexOf("Nile") >= 0) + nileOn = true; + } + pa("OBJECT: "+ob); + boolean isC = false; + if(ob instanceof ZZCursor) isC = true; + pa("IS CURSOR?: "+isC); + // if we have object which is not cursor, then nile action is impossible + if(nileOn && !(!(ob instanceof ZZCursor) && (ob != null)) ) { + ZZCell nvc1 = AwtUtil.getCursoredCell(c_cursor1, vc); + ZZCell nvc2 = AwtUtil.getCursoredCell(c_cursor2, vc); + if(nvc1==null) return; + + if(nvc1.s("d.cursor-cargo", -1)==null) { + ZZCursorReal.set(nvc1, nvc1); + ZZCursorReal.setOffs(nvc1, 0); + } + if(nvc2!=null) + if(nvc2.s("d.cursor-cargo", -1)==null) { + ZZCursorReal.set(nvc2, nvc2); + ZZCursorReal.setOffs(nvc2, 0); + } + + nile_action(id, nvc1, nvc2, key, (ZZCursor)ob); + //Nile1.module.action(id,code,target,nview,cview,key,pt,xi); + return; + } + + if(id.equals("TESTWIN")) { + AwtSystemList = target; + + // set awt dims + AwtUtil.addDims(ZZDefaultSpace.findDefaultDimlist(code.getHomeCell())); + + // Cursors + ZZCell curs = AwtSystemList.findText(AwtUtil.d_awtool, 1, "Cursors"); + if(curs == null) { + ZZCell nCurs1, nCurs2, cat1; + ZZCell cursors = AwtSystemList.N(AwtUtil.d_awtool); + cursors.setText("Cursors"); + cursors.N("d.1"); + } + + // View + ZZCell rastname, rl, rc = AwtSystemList.findText(AwtUtil.d_awtool, 1, "View"); + if(rc == null) { + rc = AwtSystemList.N(AwtUtil.d_awtool); + rc.setText("View"); + rl = rc.N("d.1"); + rl.connect("d.2", 1, rl); + rl.setText("Awtool"); + rastname = rl.N("d.1"); + rastname.setText("Awtool.View1"); + } else { + rl = rc.s("d.1"); + rastname = rl.s("d.1"); + } + + + // Bindings + ZZCell bindhome = AwtSystemList.findText(AwtUtil.d_awtool, 1, "Bind"); + if(bindhome == null) { + bindhome = AwtSystemList.N(AwtUtil.d_awtool); + bindhome.setText("Bind"); + bindhome = bindhome.N("d.1", 1); + + //ZZDefaultSpace.mkCorner(bindhome, actions); + actions(bindhome.h("d.2", 1)); + } else { + bindhome = bindhome.s("d.1"); + } + // View metrics + ZZCell metr = AwtSystemList.findText(AwtUtil.d_awtool, 1, "Metrics"); + if(metr == null) { + Dimension RV = new Dimension(400, 400); + Dimension VV = new Dimension(1000, 1000); + // create 'metrics collection' + metr = AwtSystemList.N(AwtUtil.d_awtool); + metr.setText("Metrics"); + ZZCell mnew, metrList; + + mnew = metrList = metr.N("d.1"); + + M = new AwtMetricsNormal(mnew, RV, VV, 0.0,0.0); + M.cellRepr(); + + mnew = mnew.N("d.2"); + M = new AwtMetricsFC(mnew, RV, VV, 0.0, 0.0); + M.cellRepr(); + + mnew = mnew.N("d.2"); + M = new AwtMetricsFC2(mnew, RV, VV, 0.0, 0.0); + M.cellRepr(); + + // make circle + mnew.connect("d.2", 1, metrList); + AwtUtil.setCursor(c_metrics, metrList, AwtSystemList); + + + } else { + ZZCell currentMetrics = + AwtUtil.getCursoredCell(c_metrics, AwtSystemList); + if(currentMetrics == null) { + currentMetrics = metr.s("d.1"); + AwtUtil.setCursor(c_metrics, currentMetrics, AwtSystemList); + } + M = (AwtMetrics)AwtUtil.readZObClone(currentMetrics); + M.setCell(currentMetrics); + } + + // searching for active category ... + ZZCell ac = AwtUtil.getCursoredCell(c_activeCategory, AwtSystemList); + if(ac == null) { + if(AwtSystemList.getRankLength(AwtUtil.d_categories)>1) { + ac = AwtSystemList.s(AwtUtil.d_categories); + } else { + ac = AwtSystemList.N(AwtUtil.d_categories); + ac.setText("* SCRATCH *"); + } + AwtUtil.setCursor(c_activeCategory, ac, AwtSystemList); + } + + ZZCell v = ZZDefaultSpace.newToplevelView(rc.getSpace(), + "awtool", 0, 0, M.RealView[0], M.RealView[1], + rl, null, + null, null, + null, + new Color(0xFFFFB1)); + + // Then, set bindings + ZZCell bcurs = v.getOrNewCell("d.bind", 1); + ZZCursorReal.set(bcurs, bindhome); + ZZCursorReal.setColor(bcurs, Color.black); + + + ZZCell awtc = v.h("d.2", 1).N("d.2"); + awtc.setText("AwtSystemList"); + ZZCursorReal.set(awtc, AwtSystemList); + // init shared cursors + ZZCell scursors = v.h("d.2",1).N("d.2"); + scursors.setText("SharedCursors"); + scursors.N("d.1"); + + return; + } + + AwtSystemList = AwtUtil.getAwtSysList(view.getViewcell()); + if(AwtSystemList == null && !id.equals("TESTWIN")) { + throw new ZZError("Awtool: AwtSystemList missing!!"); + } + + M = AwtUtil.getAwtMetrics(AwtSystemList); + + if(id.equals("StartDrag")) { + if(note != null) { + dragNote = note; + noteRVCoord = M.mapToRealView(note.getX(), note.getY()); + dragOffs.x = noteRVCoord.x - pt.x; + dragOffs.y = noteRVCoord.y - pt.y; + } + } else + + if(id.equals("StopDrag") && dragNote != null) { + noteVVCoord = M.mapToVirtualView(pt.x + dragOffs.x, pt.y + dragOffs.y); + dragNote.setCoord(noteVVCoord[0], noteVVCoord[1]); + dragNote.cellRepr(); + dragOffs.x = 0; dragOffs.y = 0; + dragNote = null; + } else + + if(id.equals("Dragged") && dragNote != null) { + noteVVCoord = M.mapToVirtualView(pt.x + dragOffs.x, pt.y + dragOffs.y); + dragNote.setCoord(noteVVCoord[0], noteVVCoord[1]); + ZZUpdateManager.chg(); + //dragNote.cellRepr(); + } else + + + if(id.equals("StartResize")) { + if(note != null) { + dragNote = note; + noteRVCoord = M.mapToRealView(note.getX(), note.getY()); + dragOffs.x = noteRVCoord.x - pt.x; + dragOffs.y = noteRVCoord.y - pt.y; + } + } else + + if(id.equals("StopResize") && dragNote != null) { + noteVVCoord = M.mapToVirtualView(pt.x + dragOffs.x, pt.y + dragOffs.y); + dragNote.setCoord(noteVVCoord[0], noteVVCoord[1]); + dragNote.cellRepr(); + dragOffs.x = 0; dragOffs.y = 0; + dragNote = null; + } else + + if(id.equals("Resizing") && dragNote != null) { + } else + + if(id.equals("StartCreatingNote")) { + dragCoord = pt; + // this is chanced to 'true' when dragging occurs + creatingNote = false; + } else + + if(id.equals("CreatingNote")) { + creatingNote = true; + } else + + if(id.equals("StopCreatingNote") && creatingNote) { + ZZCell newNoteCell; + AwtNote newNote; + int cx = (dragCoord.x+pt.x)>>1; + int cy = (dragCoord.y+pt.y)>>1; + double[] ndim, nvcenter = M.mapToVirtualView(cx, cy); + Dimension nd = new Dimension(Math.abs(dragCoord.x-pt.x), Math.abs(dragCoord.y-pt.y)); + ndim = M.getVirtualDimension(cx, cy, nd); + + ZZCell ac = AwtUtil.getCursoredCell(c_activeCategory, vc); + + ZZCell noteCell = + ac.h(AwtUtil.d_to).N(AwtUtil.d_to).N(AwtUtil.d_from); + + AwtUtil.createNewNote(noteCell, nvcenter, ndim); + // attach new note also to 'notes' dimension along + // active category cell. + ac.h(AwtUtil.d_notes, 1).connect(AwtUtil.d_notes, 1, noteCell); + dragCoord.x = 0; + dragCoord.y = 0; + creatingNote = false; + + } else + + if(id.equals("SetCursor1") && nc != null) { + ZZCell red = AwtUtil.getCursoredCell(c_cursor1, vc); + if(red.equals(nc)) return; + AwtUtil.setCursor(c_cursor2, red, vc); + AwtUtil.setCursor(c_cursor1, nc, vc); + if(red!=null) { + red.excise("d.nile-wins"); + nc.connect("d.nile-wins", 1, red); + nc.connect("d.nile-wins", -1, red); + } + } else + + if(id.equals("SetCursor2") && nc != null) { + ZZCell gray = AwtUtil.getCursoredCell(c_cursor2, vc); + if(gray.equals(nc)) return; + AwtUtil.setCursor(c_cursor1, gray, vc); + AwtUtil.setCursor(c_cursor2, nc, vc); + if(gray!=null) { + gray.excise("d.nile-wins"); + nc.connect("d.nile-wins", 1, gray); + nc.connect("d.nile-wins", -1, gray); + } + + } else + + if(id.equals("NewLink")) { + ZZCell c1, c2; + c1 = AwtUtil.getCursoredCell(c_cursor1, vc); + c2 = AwtUtil.getCursoredCell(c_cursor2, vc); + if(c1 != null && c2 != null && c1 != c2) { + AwtUtil.createNewLink(c1, c2); + } + } else + + if(id.equals("ChangeMetrics")) { + // save current metrics (focus, origo, etc.) + M.cellRepr(); + ZZCell mc = AwtUtil.getCursoredCell(c_metrics, vc); + mc = mc.s("d.2"); + AwtUtil.setCursor(c_metrics, mc, vc); + M = (AwtMetrics)AwtUtil.readZObClone(mc); + M.setCell(mc); + ZZUpdateManager.chg(); + } else + + if(id.equals("ResetOrigo")) { + //pa("ORIGO RESET!"); + M.setOrigo(0.0, 0.0); + ZZUpdateManager.chg(); + } else + + if(id.equals("GridOnOff")) { + //pa("GRID ON/OFF!"); + boolean gon = M.GridOn; + M.GridOn = gon ? false : true; + if(M.GridOn != gon) { + M.cellRepr(); + } + ZZUpdateManager.chg(); + } else + + if(id.equals("FocusOrigoAndSelect")) { + long elapsedTime = Long.MAX_VALUE; + long cur = System.currentTimeMillis(); + double[] vf1, vf2; + + vf1 = M.mapToVirtualView(pt.x, pt.y); + M.setFocusOrigo(pt.x, pt.y, nc); + vf2 = M.mapToVirtualView(pt.x, pt.y); + M.moveOrigo(vf1[0]-vf2[0], vf1[1]-vf2[1]); + M.cellRepr(); + + if(focusChangedLastTime > 0) { + elapsedTime = cur - focusChangedLastTime; + focusChangedLastTime = -1; + } else { + focusChangedLastTime = cur; + } + + pa("ELAPSED_TIME: "+elapsedTime); + + if(elapsedTime < 1500) { + // 'doubleclick'-focus should change also origo + // this does not work reasonably + // forceOrigoChange = true; + forceOrigoChange = false; + } else { ZZUpdateManager.chg(); } + } + + + if(id.equals("ChangeOrigo") || forceOrigoChange) { + double[] vvp = M.mapToVirtualView(pt.x, pt.y); + // new origo is wanted to be in the center of realview + double[] realOrigo = M.mapToVirtualView(M.RealView[0]>>1, + M.RealView[1]>>1); + M.moveOrigo(vvp[0]-realOrigo[0], vvp[1]-realOrigo[1]); + M.cellRepr(); + ZZUpdateManager.chg(); + } + } + + public ZOb newZOb(String id) { + if(id.equals("View1")) + return new AwtView1(); + else + return null; + } + }; + + // This is really hacky part... + static ZZCell curAct; + static void a(String key, String act) { a(key, act, null); } + static void a(String key, String act, ZZCell next) { + curAct = curAct.N("d.2", 1); + curAct.setText(key); + ZZCell n = curAct.N("d.1", 1); + n.setText("Awtool." + act); + if(next != null) + next.insert("d.3", 1, n); + } + + static void actions(ZZCell start) { + ZZCell awtact = start; awtact.setText("Awtool mode"); + ZZCell nchar = awtact.N("d.1",1); nchar.setText("Nile char"); + ZZCell nword = nchar.N("d.1", 1); nword.setText("Nile word"); + ZZCell nsent = nword.N("d.1", 1); nsent.setText("Nile sent"); + ZZCell npara = nsent.N("d.1", 1); npara.setText("Nile para"); + + ZZCell ncommon = npara.N("d.1", 1); ncommon.setText("Nile common"); + + + + curAct = nword; + // Annoying - these should be structurally + // describable!!! + a("MouseClicked1", "MouseSetCursor 0 WORD"); + a("Backspace", "BackSpace 0 WORD"); + a("Delete", "Delete 0 WORD"); + a("Alt-Backspace", "Delete 0 WORD"); + a("Ctrl-P", "Tunnel - WORD"); // P for pull + a("Ctrl-T", "Transcopy - WORD"); + a("Left", "Cursor - WORD"); + a("Right", "Cursor + WORD"); + a("Shift-Left", "AdjLeft - WORD"); + a("Shift-Right", "AdjRight + WORD"); + a("Ctrl-Left", "AdjRight - WORD"); + a("Ctrl-Right", "AdjLeft + WORD"); + a("Alt-Left", "Hop - WORD"); + a("Alt-Right", "Hop + WORD"); + a("Enter", "BreakParagraph 0 WORD"); + + a("Up", "Cursor - SENT"); + a("Down", "Cursor + SENT"); + a("Alt-Up", "Hop - SENT"); + a("Alt-Down", "Hop + SENT"); + + a("INSERT", "Insert", nchar); + a("Tab", "Mode 0 SENT", nsent); + // awtool specific + a("Alt-N", "NileOnOff", awtact); + + curAct = nsent; + a("MouseClicked1", "MouseSetCursor 0 SENT"); + a("Backspace", "BackSpace 0 SENT"); + a("Delete", "Delete 0 SENT"); + a("Alt-Backspace", "Delete 0 SENT"); + a("Ctrl-P", "Tunnel - SENT"); // P for push + a("Ctrl-T", "Transcopy - SENT"); + a("Left", "Cursor - SENT"); + a("Right", "Cursor + SENT"); + a("Shift-Left", "AdjLeft - SENT"); + a("Shift-Right", "AdjRight + SENT"); + a("Ctrl-Left", "AdjRight - SENT"); + a("Ctrl-Right", "AdjLeft + SENT"); + a("Alt-Left", "Hop - SENT"); + a("Alt-Right", "Hop + SENT"); + a("Enter", "BreakParagraph 0 SENT"); + + a("Up", "Cursor - PARA"); + a("Down", "Cursor + PARA"); + a("Alt-Up", "Hop - PARA"); + a("Alt-Down", "Hop + PARA"); + + a("INSERT", "Insert", nchar); + a("Tab", "Mode 0 CHAR", nchar); + // awtool specific + a("Alt-N", "NileOnOff", awtact); + +/* + curAct = npara; + a("MouseClicked1", "MouseSetCursor 0 PARA"); + a("Backspace", "BackSpace 0 PARA"); + a("Delete", "Delete 0 PARA"); + a("Alt-Backspace", "Delete 0 PARA"); + a("Left", "Cursor - PARA"); + a("Right", "Cursor + PARA"); + a("Shift-Left", "AdjLeft - PARA"); + a("Shift-Right", "AdjRight + PARA"); + a("Ctrl-Left", "AdjRight - PARA"); + a("Ctrl-Right", "AdjLeft + PARA"); + a("Alt-Left", "Hop - PARA"); + a("Alt-Right", "Hop + PARA"); + + a("INSERT", "Insert"); + a("Tab", "Mode 0 CHAR", nchar); + */ + + curAct = nchar; + a("MouseClicked1", "MouseSetCursor 0 CHAR"); + a("Left", "Cursor - CHAR"); + a("Right", "Cursor + CHAR"); + a("Backspace", "BackSpace 0 CHAR"); + a("Delete", "Delete 0 CHAR"); + a("Alt-Backspace", "Delete 0 CHAR"); + a("INSERT", "Insert"); + a("Tab", "Mode 0 WORD", nword); + a("Enter", "BreakParagraph 0 CHAR"); + + a("Ctrl-C", "PUICopy 0 CHAR"); + + a("Up", "Cursor - WORD"); + a("Down", "Cursor + WORD"); + // awtool specific + a("Alt-N", "NileOnOff", awtact); + + // awtool acts + curAct = awtact; + a("MouseStartDrag", "StartDrag"); + a("MouseDragged1", "Dragged"); + a("MouseReleased1", "StopDrag"); + a("Shift-MouseStartDrag", "StartCreatingNote"); + a("Shift-MouseDragged1", "CreatingNote"); + a("Shift-MouseReleased1", "StopCreatingNote"); + a("Shift-MouseClicked3", "ChangeOrigo"); + a("MouseClicked3", "FocusOrigoAndSelect"); + a("Shift-MouseClicked1", "SetCursor2"); + a("MouseClicked1", "SetCursor1"); + a("l", "NewLink"); + a("m", "ChangeMetrics"); + a("g", "GridOnOff"); + a("r", "ResetOrigo"); + a("Alt-N", "NileOnOff", nchar); + + } +} diff --git a/Modules/awtool/BooleanMesh.java b/Modules/awtool/BooleanMesh.java new file mode 100644 index 0000000..3a6a309 --- /dev/null +++ b/Modules/awtool/BooleanMesh.java @@ -0,0 +1,78 @@ +/* +BooleanMesh.java + * + * Copyright (c) 2000-2001 Ted Nelson and Tuomas Lukka + * Copyright (c) 2000-2001 Benjamin Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Kimmo Wideroos + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +public abstract class BooleanMesh { + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + static String d_1 = "d.1"; static String d_2 = "d.2"; + static public ZZCell bStructure = null; + static public Hashtable bOperators = new Hashtable(); + + /* + */ + public BooleanMesh(ZZCell bs) { + bStructure = bs; + bOperators.put("AND", new boolean[][]{{false, false}, {false, true}}); + bOperators.put("OR", new boolean[][]{{false, true}, {true, true}}); + bOperators.put("XOR", new boolean[][]{{false, true}, {true, false}}); + } + + public boolean evaluate(ZZCell nhc) { return evaluate(bStructure, nhc); } + + private boolean evaluate(ZZCell bElem, ZZCell nhc) { + String bt = bElem.getText(); + p("belem:"+bt+" c:"+nhc.getText()); + ZZCell arg1, arg2; + int i = 0, j = 0; + if(bOperators.containsKey(bt)) { + // add exception handling here! + arg1 = bElem.s(d_1); arg2 = bElem.s(d_2); + p("arg1:"+arg1.getText()); + p("arg2:"+arg2.getText()); + if(evaluate(arg1, nhc)) i = 1; + if(evaluate(arg2, nhc)) j = 1; + p("i:"+i+" j:"+j); + boolean retv = ((boolean[][])bOperators.get(bt))[i][j]; + p("RETV: "+retv); + return retv; + } else { + // compare bElem (=categoryname) and c + p("TEST! "+nhc.getText()+" =?= "+bElem.getText()); + return testBelonging(nhc, bElem); + } + } + + public abstract boolean testBelonging(ZZCell c, ZZCell category); + +} + + + + diff --git a/Modules/awtool/README b/Modules/awtool/README new file mode 100644 index 0000000..4a6ee0d --- /dev/null +++ b/Modules/awtool/README @@ -0,0 +1,58 @@ + +A(ssociative) writing tool -demo +-------------------------------- + +Althought you cannot actually write with this demo at the moment, +it is (however) possible to + +- create new notes by dragging mouse and keeping + mouse1-key pressed +- drag and drop notes created before +- link notes by attaching cursors (click mouse1 / shift-mouse1 + on a note) to a pair of notes and pressing 'l' (uncapitalized 'L') +- change metrics by pressing 'm' (currently 3 possibilities) +- change focus (click mouse3-button) +- change origo (click shift-mouse3) + +To start: +- create new action 'Awtool.TESTWIN' in zz-system +- use it to invoke awtool + +About the view: +- Real view (rendered part) is mutable +- Virtual view is fixed, all objects' places + are based on virtual view coordinates (-1.0= 0; i--) + r.run(); + long t1 = System.currentTimeMillis(); + nt *= 2; + diff = t1 - t0; + } while(diff < 1500); + p(s+": "+nt+" iter, "+diff+" ms, per iter: "+ + (long)(1000000 * diff / (float)nt) + " ns"); + } + + /** Run the given tests, time them and print out the results. + * Each test should be relatively fast to execute. + * @param tests Triplets of String, String, Runnable: + * first string is a unique ID for the test, + * second string a human-readable explanation (without newlines) + * and the Runnable is the test itself. + */ + public void run(Object[] tests) { + for(int i=0; i"); + // Create people rank in alphabetical order + rs = st.executeQuery("select * from members order by name"); + ZZCell prev = null; + while(rs.next()) { + ZZCell curr = (ZZCell)id2mem.get(rs.getString(1)); + + if(prev != null) prev.connect("d.people", 1, curr); + prev = curr; + } + + // Create sig rank in alphabetical order + rs = st.executeQuery("select * from sigs order by name"); + prev = null; + while(rs.next()) { + ZZCell curr = (ZZCell)id2sig.get(rs.getString(1)); + + if(prev != null) prev.connect("d.insigs", 1, curr); + prev = curr; + } + + + + + p("Rels: "); + + // Insert relcells after the positions table + rs = st.executeQuery("select * from positions"); + while(rs.next()) { + String pers = rs.getString(1); + String sig = rs.getString(2); +// p("Rel: "+pers+" "+sig); + ZZCell pc = (ZZCell)id2mem.get(pers); + ZZCell sc = (ZZCell)id2sig.get(sig); + if(pc == null || sc == null) + throw new Error("No such relation "+pers+" "+sig); + ZZCell relc = pc.N("d.insigs",1); + sc.insert("d.people", 1, relc); + relc.setText("+"); + } + rs.close(); + + // Sort the ranks of the in-which-sigs tables. + + for(Enumeration e = id2mem.elements(); + e.hasMoreElements(); ) { + ZZCell c = (ZZCell)e.nextElement(); + ZZUtil.sortRank(c, "d.insigs", 1, + new DHeadComp("d.people"), false); + } + + for(Enumeration e = id2sig.elements(); + e.hasMoreElements(); ) { + ZZCell c = (ZZCell)e.nextElement(); + ZZUtil.sortRank(c, "d.people", 1, + new DHeadComp("d.insigs"), false); + } + + st.close(); + db.close(); + + } + } /* else if(id.equals("IMPORT")) { + // XXX How to give 2 arguments: the file name and the home cell + (new XML()).load(new File(target.getText()), + }*/ + } catch(SQLException e) { + System.out.println(e); + e.printStackTrace(); + } catch(ClassNotFoundException e) { + System.out.println(e); + e.printStackTrace(); + } + } + }; +} diff --git a/Modules/database/createscript.pl b/Modules/database/createscript.pl new file mode 100644 index 0000000..a05ccd8 --- /dev/null +++ b/Modules/database/createscript.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl +# +# Create a sample database. +# Use the linux kernel CREDITS file as input. + + +print <<'STOP'; +DROP TABLE members; +DROP TABLE positions; +DROP TABLE sigs; + +CREATE TABLE members ( + id INT4, + name TEXT, + address TEXT, + phone TEXT, + email TEXT, + PRIMARY KEY(id) +); + +CREATE TABLE positions ( + person INT4, + sig INT4 +/* type TEXT */ +); + +CREATE TABLE sigs ( + id INT4, + name TEXT, + PRIMARY KEY(id) +); +STOP + +$/ = "\n\n"; + +$id = 0; + + +while(<>) { + /^\s*N:/ or next; + s/'//g; + my %h; + for(split "\n") { + /^([A-Z]): (.*)$/ or next; + push @{$h{$1}}, $2; + } + $phone = int(1000000 + rand 9000000); + $phone =~ s/(...)(....)/\1-\2/g; + print "INSERT INTO members VALUES ($id, '$h{N}[0]', '$h{S}[0]', '$phone', '$h{E}[0]');\n"; + $id++; + last if $id > 100; +} + +$sid = 0; +for(qw/filesys mm drivers boot console vfs/) { + print "INSERT INTO sigs VALUES ($sid, '$_');\n"; + $sid++; +} + +my %pos; + +for(1..120) { + $pers = int rand $id; + $sig = int rand $sid; + next if $pos{$pers}{$sig}++; + print "INSERT INTO positions VALUES ($pers, $sig);\n"; +} + diff --git a/Modules/database/zz.queries b/Modules/database/zz.queries new file mode 100644 index 0000000..6253521 --- /dev/null +++ b/Modules/database/zz.queries @@ -0,0 +1,18 @@ + +-- Taulut + +SELECT * FROM members; + +SELECT * FROM positions; + +SELECT * FROM sigs; + +-- Kaikkien tekijöiden kaikki projektit + +SELECT members.name,sigs.name FROM members, positions, sigs WHERE members.id = positions.person AND sigs.id = positions.sig ORDER BY members.name, sigs.name; + +-- Kaikkien projektien kaikki tekijät + +SELECT sigs.name,members.name FROM members, positions, sigs WHERE members.id = positions.person AND sigs.id = positions.sig ORDER BY sigs.name, members.name; + + diff --git a/Modules/database/zz.sql b/Modules/database/zz.sql new file mode 100644 index 0000000..1c60f0e --- /dev/null +++ b/Modules/database/zz.sql @@ -0,0 +1,29 @@ + +CREATE TABLE members ( + id INT4, + fname TEXT, + lname TEXT, + address TEXT, + phone TEXT, + email TEXT, + PRIMARY KEY(id) +); + +CREATE TABLE positions ( + person INT4, + sig INT4 +/* type TEXT */ +); + +CREATE TABLE sigs ( + id INT4, + name TEXT, + PRIMARY KEY(id) +); + +INSERT INTO members VALUES + (1,'Henna','Koskinen','Kuusikkokuja 4','321-564356','henna43@hotmail.com'); +INSERT INTO sigs VALUES + (1,'helicopters'); +INSERT INTO positions VALUES + (1,1); diff --git a/Modules/daytimedemo/Calendar2.zob b/Modules/daytimedemo/Calendar2.zob new file mode 100644 index 0000000..12ee2cb --- /dev/null +++ b/Modules/daytimedemo/Calendar2.zob @@ -0,0 +1,162 @@ +/* +Calendar2.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; + +public class Calendar2 implements FlobView, ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public ZOb newZOb(String id) { + if(id.equals("R")) + return new Calendar2(); + return null; + } + }; + + STRUCTPARAMS { + Font nfont + = new Font("SansSerif", Font.PLAIN, 16); + + Font bfont + = new Font("SansSerif", Font.BOLD, 16); + } + + FontMetrics nfm, bfm; + + INITIALIZE { + nfm = FONTMETRICS(nfont); + bfm = FONTMETRICS(bfont); + } + + final String[] txts = new String[] { + "Vk", "M", "T", "K", "T", "P", "L", "S" + }; + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + Dimension s = into.getSize(); + + final int x = s.width/2 / 10; + final int y = s.height / 10; + final int w = s.width/2 - 2 * x; + final int h = s.height - 2 * y; + + final int x2 = x + s.width/2; + + final int xm = w / 8; + final int ym = h / 7; + + Dimension c = fact.getSize(null, 1); + int cw = c.width; + int ch = c.height; + + // Find the first day of the month + + ZZCell curday = accursed.h("d.event").h("d.events"); + ZZCell mfirst = curday.h("d.day"); + + + + + if(mfirst.s("d.weekday") == null) { + into.add(new Renderable() { + { d = 1; } + public void render(Graphics g) { + g.setColor(Color.red); + g.setFont(new Font("SansSerif", Font.BOLD, 32)); + g.drawString("Not calendar data", 20, 40); + } + }); + return; + } + int day = Integer.parseInt(mfirst.s("d.weekday").t()); + final int week = Integer.parseInt(mfirst.s("d.weekday",2).t()); + + into.add(new Renderable() { + { d = 50; } + public void render(Graphics g) { + Color old = g.getColor(); + g.setColor(Color.gray); + g.setFont(nfont); + g.drawRect(x, y, w, h); + g.drawLine(x+xm, y, x+xm, y+h); + g.drawLine(x, y+ym, x+w, y+ym); + int fh = nfm.getHeight(); + for(int i=0; i<8; i++) { + int tw = nfm.stringWidth(txts[i]); + g.drawString(txts[i], x+(xm-tw)/2+i*xm, y+(ym+fh)/2); + } + for(int i=0; i<6; i++) { + int tw = nfm.stringWidth(""+(i+week)); + g.drawString(""+(i+week), x+(xm-tw)/2, y+(ym+fh)/2+(i+1)*ym); + } + g.setColor(new Color(0xb0b0b0)); + for(int i=0; i<5; i++) { + g.drawLine(x, y+(2+i)*ym, x+w, y+(2+i)*ym); + } + } + }); + + LoopDetector l = new LoopDetector(); + int row = 0; + for(ZZCell mday = mfirst; mday != null; mday = mday.s("d.day")) { + l.detect(mday); + boolean hasEv = (mday.s("d.events") != null); + + fact.makeFlob(into, mday, mday, (hasEv ? (float)1.8 : 1), + x+1+(1+day)*xm, y+1+(1+row)*ym, 2, xm-2, ym-2); + + if(mday == curday) { + // Ring it + + } + day += 1; + if(day >= 7) row ++; + day %= 7; + } + + row = 0; + int fh = nfm.getHeight(); + for(ZZCell curev = curday.s("d.events"); + curev != null && curev != curday; + curev = curev.s("d.events")) { + fact.makeFlob(into, curev, curev, 1, + x2 + 10, y + (ch+2)*row, 1, w-10-cw, ch); + ZZCell txt = curev.s("d.event"); + fact.makeFlob(into, txt, txt, 1, + x2 + w - cw, y + (ch+2)*row, 1, cw, ch); + row ++; + } + + + } +} +// vim: set syntax=java : + diff --git a/Modules/daytimedemo/ClockCellView.zob b/Modules/daytimedemo/ClockCellView.zob new file mode 100644 index 0000000..81efbd9 --- /dev/null +++ b/Modules/daytimedemo/ClockCellView.zob @@ -0,0 +1,116 @@ +/* +ClockCellView.zob + * + * Copyright (c) 2001, Benja Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benja Fallenstein + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** A cell view that shows the daytime demo clock, using a scene flob. + * For use with ideosyncratic cell view. Create the cell to be shown as a + * clock. Posward on d.3, connect the clock cell to a d.2 rank of appointments + * in the regular DayTimeDemo structure (see DayTimeDemo.zob and the + * CyberText article pictures). Then, from the clock cell negwards on + * d.cellview create a new cell and write the cell view's name, e.g. + * "Clock Cellview," in it. From that cell, create a new cell poswards on d.1 + * and write "DayTimeDemo.C" (of course w/o quotes) in it. Use F2 to switch + * to the ideosyncratic cell view, and the clock cell should change its + * appereance to a DayTimeDemo clock. (Best viewed with StretchVanishing or + * Quad view, so that it's not shown that small.) + */ + +public class ClockCellView implements FlobFactory, ZOb { +public static final String rcsid = "$Id: ClockCellView.zob,v 1.3 2001/03/18 17:50:16 bfallenstein Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + STRUCTPARAMS { + Font txtfont + = new Font("Serif", Font.BOLD, 14); + + Font clkfont + = new Font("SansSerif", Font.PLAIN, 11); + } + + public Dimension getSize(ZZCell c, float fract) { + return new Dimension((int)(150*fract), (int)(150*fract)); + } + + DayTimeDemo dtd = new DayTimeDemo(); + + INITIALIZE { + dtd.txtfont = txtfont; + dtd.clkfont = clkfont; + dtd.txtfm = FONTMETRICS(txtfont); + dtd.clkfm = FONTMETRICS(clkfont); + } + + public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int d, int w, int h) { + + FlobSet sc = new FlobSet(new Dimension(w, h), Color.white, Color.black, + ScalableFont.fmComp); + dtd.raster(sc, null, null, null, c.getRootclone().h("d.3", 1)); + + SceneFlob sf = new SimpleSceneFlob(x, y, d, w, h, c, sc); + CellFlobFactory1.addSolidColors(into, sf, sf); + into.add(sf); + return sf; + } + + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + float xfract, float yfract) { + Dimension d = getSize(c, fract); + return makeFlob(into, c, handleCell, fract, + (int)(x-xfract*d.width), + (int)(y-yfract*d.height), + depth, d.width, d.height); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth, Dimension d) { + if(d == null) d = getSize(c, fract); + int x, y; + x = p.x - d.width/2; y = p.y - d.height/2; + + if(xalign < 0) x = p.x; + if(xalign > 0) x = p.x - d.width; + if(yalign < 0) y = p.y; + if(yalign > 0) y = p.y - d.height; + p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign); + return makeFlob(into, c, handleCell, fract, x, y, + depth, d.width, d.height); + } + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) { + return centerFlob(into, c, handleCell, fract, p, xalign, yalign, + depth, null); + } +} + +// vim: set syntax=java : diff --git a/Modules/daytimedemo/DayTimeDemo.zob b/Modules/daytimedemo/DayTimeDemo.zob new file mode 100644 index 0000000..efcc1e2 --- /dev/null +++ b/Modules/daytimedemo/DayTimeDemo.zob @@ -0,0 +1,174 @@ +/* +DayTimeDemo.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** A simple raster showing times of day along a circle. + * The structure is described along three dimensions: + * hierarchy, sibling and cross-reference (d.1, d.2 and d.3 by default). + * On these, the hierarchy is arranged as a corner list with an empty + * corner cell, and the cross-references are simply siblings + * connected. + *

    + * The structure is specified as a rank on d.2 of d.1 lists: + * start, end, type, text. Type's root clone will have the color + * of the type on d.1. + *

    + * The whole rank on d.2 is read. + */ + +public class DayTimeDemo implements FlobView, ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public ZOb newZOb(String id) { + if(id.equals("R")) + return new DayTimeDemo(); + if(id.equals("C")) + return new ClockCellView(); + return null; + } + }; + + STRUCTPARAMS { + Font txtfont + = new Font("Serif", Font.BOLD, 14); + + Font clkfont + = new Font("SansSerif", Font.PLAIN, 11); + } + + FontMetrics txtfm, clkfm; + + INITIALIZE { + txtfm = FONTMETRICS(txtfont); + clkfm = FONTMETRICS(clkfont); + } + + static final String next = "d.2"; + static final String hier = "d.1"; + static final String cross = "d.3"; + + static final int time2deg(String time) { + int i = time.indexOf(":"); + if(i < 0) return 0; + String t1 = time.substring(0,i); + String t2 = time.substring(i+1); + int h = -1; + int m = -1; + try { + h = Integer.parseInt(t1); + m = Integer.parseInt(t2); + } catch(NumberFormatException e) { + System.out.println("Exc: "+e); + } + return -(int)(360 * (h*60.0 + m) / (24*60)) - 90; + } + + static final Point deg2pt(int deg, int w, int h) { + return new Point((int)(w/2*Math.cos(deg * Math.PI / 180)), + -(int)(h/2*Math.sin(deg * Math.PI / 180))); + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + Dimension s = into.getSize(); + + final int x = s.width / 10; + final int y = s.height / 10; + final int w = s.width - 2 * x; + final int h = s.height - 2 * y; + + // Clock face. + into.add(new Renderable() { + { d = 50; } + public void render(Graphics g) { + Color old = g.getColor(); + g.setColor(Color.black); + g.setFont(clkfont); + for(int i=0; i<24; i++) { + int and = time2deg(i+":00"); + // g.fillArc(x, y, w, h, and, 1); + Point p = deg2pt(and, w, h); + p.x *= 1.05; + p.y *= 1.05; + p.translate(x+w/2, y+h/2); + g.drawLine(x+w/2, y+h/2, p.x, p.y); + if(i % 2 == 0) { + String str = i+":00"; + g.drawString(str, p.x - clkfm.stringWidth(str)/2 , p.y); + } + } + g.setColor(old); + } + }); + + for( + ZZCell cur = accursed.h("d.1", -1).h("d.2", -1); + cur != null; + cur = cur.s("d.2", 1)) { + ZZCell c = cur; + String start = c.getText(); c = c.s("d.1", 1); + String end = c.getText(); c = c.s("d.1", 1); + ZZCell meet = c.h("d.clone", -1).s("d.1", 1); + String col = "0xffffff"; + if(meet != null) col = meet.getText(); + c = c.s("d.1", 1); + + final String text = c.getText(); + final int sang = time2deg(start); + final int eang = time2deg(end); + final Color color = Color.decode(col); + + // now, render it. + into.add(new Renderable() { + { d = 50; } + public void render(Graphics g) { + g.setColor(color); + g.fillArc(x, y, w, h, sang, eang-sang); + }}); + into.add(new Renderable() { + { d = 45; } + public void render(Graphics g) { + g.setFont(txtfont); + Point p = deg2pt((sang+eang)/2, w, h); + p.x *= 0.8; + p.y *= 0.8; + p.translate(x+w/2, y+h/2); + g.setColor(Color.black); + g.drawString(text, p.x, p.y); + g.fillOval(p.x-8, p.y-8, 8, 8); + }}); + + + } + + } +} +// vim: set syntax=java : diff --git a/Modules/extern/Extern.java b/Modules/extern/Extern.java new file mode 100644 index 0000000..5372662 --- /dev/null +++ b/Modules/extern/Extern.java @@ -0,0 +1,83 @@ +/* +Extern.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.io.*; +import java.awt.*; + +/** + * Module to handle external commands. At the moment only + * EXECBROWSER is implemented. To start netscape execbrowser with + * empty target cell. If there is text in the target cell, + * netscape -remote openURL("") is executed. + */ +public class Extern { + + public static final String rcsid = "$Id: Extern.java,v 1.4 2000/09/19 10:32:02 ajk Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + static public ZZModule module = new ZZModule() { + public void action(String id, ZZCell code, + ZZCell target, + ZZView v, ZZView cv, + String key, Point pt, + ZZScene xi) { + + + try { + p("Extern ACTION!"); + /* + * XXX: + * Add a chech to see whether a netscape or mozilla + * is running. + * + */ + if(id.equals("EXECBROWSER")) { + Process p = null; + String s = target.getText(); + if ( ! s.equals( "" ) ){ + p("netscape -remote openURL(" + s + ")" ); + p = Runtime.getRuntime().exec( + "netscape -remote openURL(" + s + ") "); + p("" + p); + + } + else { + Runtime.getRuntime().exec("netscape"); + } + } else { + pa("NO SUCH METHOD!! "); + } + + } + catch (IOException ex){ + p("" + ex); + } + } + + }; +} diff --git a/Modules/hypergenealogy/HyperGenealogy.zob b/Modules/hypergenealogy/HyperGenealogy.zob new file mode 100644 index 0000000..491d5cc --- /dev/null +++ b/Modules/hypergenealogy/HyperGenealogy.zob @@ -0,0 +1,283 @@ +/* +HyperGenealogy.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** A simple keyframe-based lifeline/meeting tracer. + * There is: one cell for each meeting, one cell for each person + * and one cell for each person of a meeting. + * We plot the cells of the people and meetings. + * The meeting cell can have a short label. The fuller explanation + * should be elsewhere. + *

    + * Dimension names give the dimension along which to find the cell + * with the number, except "time", which shows the keyframes. + *

    + * All numbers are floats between 0 and 1. + *

    + * There must be a root cell which starts the list of all persons + * on d.persons and the timeline on d.events. + */ + +public class HyperGenealogy implements FlobView, ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public ZOb newZOb(String id) { + if(id.equals("R")) + return new HyperGenealogy(); + return null; + } + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + } + }; + + STRUCTPARAMS { + Font meetfont + = new Font("Serif", Font.BOLD, 11); + + } + + FontMetrics meetfm; + + INITIALIZE { + meetfm = FONTMETRICS(meetfont); + } + + + static public class dc { + /** The dimension from the meeting cell to the participants, + * and from the root to the peoples' cells. + */ + final String persons = "d.persons"; + /** The dimension from the person's cell to the events in his life, + * and from the root cell to all timeline cells. + * All these cells should go forwards in the "time" dimension. + */ + final String events = "d.events"; + /** The dimension from a timeline cell to meeting cell. + */ + final String at = "d.at"; + } + static dc d = new dc(); + + public float tofloat(ZZCell c) throws NumberFormatException { + return (Float.valueOf(c.getText())).floatValue(); + } + + /** Return the value the given cell has for the particular dimension. + * This routine understands the special dimension time, + * which it takes to mean the number at the headcell of + * d.persons + * and d.at. That cell is assumed to be on the timeline. + */ + public float dim(ZZCell c, String dimname) { + try { + ZZCell dc; + if(dimname.equals("time")) { + dc = c.h(d.persons, -1).h(d.at, -1); + if(dc == c) dc = null; + } else { + dc = c.s(dimname, 1); + } + if(dc == null) return -1; + return tofloat(dc); + } catch(NumberFormatException e) { + return -1; + } + } + + + /** + * @param from Meeting cell + */ + public void place(FlobSet into, int x, int y, int w, int h, + FlobFactory fact, + String[] dims, ZZCell from, int depthleft) { + + from = from.h(d.persons); + + for(ZZCell c = from.s(d.persons, 1); + c != null; + c = c.s(d.persons, 1)) { + + if(into.findFlob("", c) != null) + return; + + float dx = dim(c, dims[0]); + if(dx < 0) return; + float dy = dim(c, dims[1]); + if(dy < 0) return; + + Flob flob = fact.placeFlob(into, from, c, + 1, + (int)(x + dx * w), (int)(y + dy * h), + 1, + (float)0.5, (float)0.5); + Flob f2 = fact.placeFlob(into, c.h(d.events), c, + 1, + (int)(x + dx * w), (int)(y + dy * h + flob.h/2), + 1, + (float)0.5, (float)0.0); + f2.flobPath = "evPers"; + + if(depthleft <= 0) continue; + ZZCell n = c.s(d.events, 1); + if(n != null) + place(into, x, y, w, h, fact, dims, n, depthleft-1); + n = c.s(d.events, -1); + if(n != null) + place(into, x, y, w, h, fact, dims, n, depthleft-1); + } + } + + /** Place the cells at a given instant of time. + */ + public void placeTime(FlobSet into, int x, int y, int w, int h, + FlobFactory fact, + String[] dims, ZZCell from, float at) { + // This assumes the root... + ZZCell root = from; + LoopDetector ld = new LoopDetector(); + p("Placetime"); + for(ZZCell p = root.s(d.persons); p != null; p = p.s(d.persons)) { + ld.detect(p); + // Find the right time interval. Move poswards until greater + // or eq than current. + ZZCell prevev = null; + float prevt = 0; + float t = 0; + ZZCell ev; + p("Pt1: "+p); + for(ev = p.s(d.events); ev != null; ev = ev.s(d.events)) { + t = dim(ev, "time"); + p("Pt2: "+ev+" "+t); + if(t >= at) break; + prevev = ev; + prevt = t; + } + p("Pt3: "+prevev+" "+ev+" "); + + float dx, dy; + if(ev == null) continue; + + if(prevev == null) { + if(t > at) continue; + dx = dim(ev, dims[0]); if(dx < 0) continue; + dy = dim(ev, dims[1]); if(dy < 0) continue; + } else { + float f = 1 - (at - prevt) / (t - prevt); + // Now we've got it in the aim... get the coordinates + // and interpolate. + float dx0 = dim(prevev, dims[0]); if(dx0 < 0) continue; + float dx1 = dim(ev, dims[0]); if(dx1 < 0) continue; + float dy0 = dim(prevev, dims[1]); if(dy0 < 0) continue; + float dy1 = dim(ev, dims[1]); if(dy1 < 0) continue; + + + dx = f * dx0 + (1-f) * dx1; + dy = f * dy0 + (1-f) * dy1; + } + + Flob flob = fact.placeFlob(into, p, p, + 1, + (int)(x + dx * w), (int)(y + dy * h), + 1, + (float)0.5, (float)0.5 + ); + + // ZZCell + } + } + + // If accursed cell is a timeline cell, do all persons + public void raster(final FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + Dimension s = into.getSize(); + + int x = s.width / 10; + int y = s.height / 10; + int w = s.width - 2 * x; + int h = s.height - 2 * y; + + if(accursed.s(d.at, 1) != null) { + placeTime(into, x, y, w, h, fact, dims, + accursed.h(d.events), tofloat(accursed)); + } else { + place(into, x, y, w, h, fact, dims, accursed.h(d.persons), 3); + } + + // selection: 3 next/prev meetings of current person, + // 1 next/prev of those he met. + + final LineDecor.Builder ldb = new LineDecor.Builder(into, null); + final LineDecor.Builder ldbm = new LineDecor.Builder(into, Color.red); + final Hashtable done = new Hashtable(); + + into.iterDepth(new FlobSet.DepthIter() { + final void dline(Flob from, String dim, int dir, + LineDecor.Builder bu) { + ZZCell c = from.c.s(dim, dir); + if(c == null) return; + if(done.get(c) != null) return; + Flob to = into.findFlob("", c); + if(to == null) return; + //draw the line + bu.l(from.x, from.y+from.h/2, to.x, to.y+to.h/2); + } + public void act(Flob[] flobs, int start, int n) { + ldb.startl(4*n, flobs[start].d); + ldbm.startl(4*n, flobs[start].d); + for(int i=start; i 1) { + higherdim++; + p("no el on hdim "+higherdim); + if(higherdim == dim) higherdim++; + } + if(level == 1 || higherdim >= dims.length) { + p("Iter.Dims -- no higher dim on dim "+dim); + dim++; + higherdim = 0; + if(dim >= dims.length) { + p("Iter.Dims -- no dim on level "+level); + level++; + if(level > maxlevel) return null; + dim = 0; higherdim = 1; + p("Iter.Dims level: "+level); + boolean doContinue = false; + for(int d=0; d 0) doContinue = true; + higher[d] = curr[d]; + curr[d] = new Vector(); + } + if(!doContinue) return null; + } + } + if(level > 1) enum = higher[higherdim].elements(); + else enum = higher[0].elements(); + } + iter.start((Iter.Step)enum.nextElement(), dims[dim]); + } + + curr[dim].addElement(iter.here); + p("ret: "+iter.here.cell); + return iter.here; + } + + public void stop() { iter.stop(); } +} diff --git a/Modules/iter/EnumVanishingView.zob b/Modules/iter/EnumVanishingView.zob new file mode 100644 index 0000000..0519f19 --- /dev/null +++ b/Modules/iter/EnumVanishingView.zob @@ -0,0 +1,177 @@ +/* +EnumVanishingView.zob + * + * Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein, based on VanishingView by Tuomas Lukka + */ + + +package org.gzigzag; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +/** A reimplementation of the vanishing raster. + * Much simpler than the original one since this one does not try + * to do the hard rasters as well. + */ + +public class EnumVanishingView implements FlobView, ZOb { +public static final String rcsid = "$Id: EnumVanishingView.zob,v 1.1 2000/11/16 20:28:53 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + // Following are the parameters out of which the constructor + // is created. + + STRUCTPARAMS { + + /** The factor to shrink the cells with when moving away from + * center. + */ + float[] shrink // 2..2 + = new float[] {(float)0.9, (float)0.9}; + + /** The factor the center cell is enlarged with from default. + */ + float[] initmul // 2..2 + = new float[] {(float)1.6, (float)1.6}; + + /** The factor to enlarge the center cell on top of initmul. + * This only has an effect on the center cell whereas initmul + * affects all cells. + */ + float[] centermul // 2..2 + = new float[] {(float)1.0, (float)1.0}; + + /** The distance between neighbouring cells. + */ + int gap + = 5; + + /** The depth to raster to. + */ + int depth + = 5; + + /** The precedence order of dimensions. + */ + int[] pref // 2..5 + = new int[] {0, 1, 2}; + + /** Whether to allow cell sizes to vary. + */ + boolean varsize + = false; + + } + + // XXX This should be a structparam later on. + FlobDecorator linker = new StdLinks(); + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + Dimension fs = into.getSize(); + + // Precalculate sizes and gaps. + int[] gaps = new int[depth]; + Dimension[] size = new Dimension[depth+1]; + float[] sizfact = new float[depth+1]; + + float xf = initmul[0], xf0 = xf; + float yf = initmul[1], yf0 = yf; + sizfact[0] = yf; + Dimension d0 = fact.getSize(null, yf); + Dimension d = (varsize ? fact.getSize(accursed, yf) : d0); + + for(int i=0; i0 ? 1 : -1; + int dpt = once.here.nth; + + // Alignments + int fxa, fya, txa, tya; + if(dim.dim == 0) { fxa=dir; txa=-dir; fya=0; tya=0; } + else if(dim.dim == 1) { fxa=0; txa=0; fya=dir; tya=-dir; } + else { fxa=dir; fya=dir; txa=-dir; tya=-dir; } + + Point p = f.getPoint(fxa, fya); + Point q = ZZUtil.movePoint(p, fxa, fya, gaps[dpt]); + + Flob g = fact.centerFlob(into, c, c, sizfact[dpt], q, txa, tya, + d1+dpt*dm, size[dpt]); + once.here.info = g; + p("To "+once.here+" assign "+g); + } + + linker.decorate(into, "", view); + + // Do the dimensions. + if(true) + ZZUtil.showFlobDims(into, fact, view, 3); + } + +} \ No newline at end of file diff --git a/Modules/iter/Iter.java b/Modules/iter/Iter.java new file mode 100644 index 0000000..aedeca4 --- /dev/null +++ b/Modules/iter/Iter.java @@ -0,0 +1,212 @@ +/* +Iter.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; +import java.util.*; + +/** Help for iterating along ranks in various ways. + * A proposed alternative to ZZIter. + * XXX make constructors work (how?) + * XXX remove verbose debugging messages + * XXX make MUCH faster! + */ + +public class Iter { +public static final String rcsid = "$Id: Iter.java,v 1.1 2000/11/16 20:28:53 bfallenstein Exp $"; + public static final boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + + static public class Step { + public ZZCell cell; + public Step from; + public int nth; + + public Object info; + + // Do not need to be set (then, dir == null). + public String dim = null; + public int dir; + + public Step(ZZCell c) { from = null; cell = c; nth = 0; } + public Step(Step f, ZZCell c, int n) { from = f; cell = c; nth = n; } + + public Step go(ZZCell c) { return new Step(this, c, nth+1); } + public Step go(String dim, int dir) { + p("step "+cell+" "+dim+" "+dir); + ZZCell tocell = cell.s(dim, dir); + p("tocell "+tocell); + if(tocell == null) return null; + Step res = go(tocell); + p("res.cell "+res.cell); + res.dim = dim; res.dir = dir; + return res; + } + + public String toString() { return "[Iter.Step for "+cell+"]"; } + } + + static public abstract class Any { + public Step here, root; + public boolean included; + + protected abstract Step getNext(); + protected void doStart() {} + +// public Any(boolean included) { this.included = included; } + public ZZCell start(Step s) { + here = s; root = s; + doStart(); + if(!included) next(); + return here != null ? here.cell: null; + } + public ZZCell next() { + if(here == null) return null; + here = getNext(); + return here != null ? here.cell : null; + } + public boolean more() { return here != null; } + public void stop() { here = null; } + } + + + static public abstract class Dim extends Any { + String dim; int fdir = 1; + +// public Dim(String dim, int fdir, boolean included) { +// this.dim = dim; +// this.fdir = fdir; +// this.included = included; +// } + + public void start(Step s, String dim) { + this.dim = dim; start(s); + } + public void start(Step s, String dim, int fdir) { + this.dim = dim; this.fdir = fdir; start(s); + } + } + + + static public class Rank extends Dim { + protected Step getNext() { return here.go(dim, fdir); } + } + + + static public class Alter extends Dim { + /** Current position negwards and poswards. */ + Step neg, pos; + + public int ind; + + public void doStart() { + neg = here.go(dim, -fdir); + pos = here.go(dim, fdir); + p("alter start: "+pos+" "+neg+" // "+(pos==root?"yes":"no")); + ind = 0; + } + protected Step getNext() { + if(neg == null && pos == null) { p("alter null"); return null; } + // Trick: always change ind, only after see if we have something + // to return. If not, recurse and get the next one from the other side. + Step res; + if(ind <= 0) { + ind = -ind; + ind ++; + if(pos == null) + return getNext(); + res = pos; + pos = pos.go(dim, fdir); + p("alter pos from "+res+" to "+pos); + } else { + ind = -ind; + if(neg == null) + return getNext(); + res = neg; + neg = neg.go(dim, -fdir); + p("alter neg from "+res+" to "+neg); + } + p("alter: "+res); + // Don't loop XXX doesn't work yet +// if(neg!=null && pos!=null && neg.cell==pos.cell) return null; + return res; + } + public void stop() { + if(ind > 0) neg = null; + else if(ind < 0) pos = null; + else super.stop(); + } + } + + + static public abstract class Filter extends Any { + protected Any iter; + + protected abstract boolean check(); + protected void accepted() {} + +// public Filter(Any iter) { this.iter = iter; } + public ZZCell start(Step s) { + iter.start(s); + here = iter.here; + doStart(); + return here.cell; + } + public ZZCell next() { + if(here == null) return null; + do { + p("Filter get next..."); + iter.next(); + here = iter.here; + p("Filter check: "+here); + if(here == null) return null; + } while(!check()); + accepted(); + p("Filter accept "+here); + return here.cell; + } + public void stop() { iter.stop(); } + protected Step getNext() { throw new ZZError("getNext on Filter"); } + } + + + static public class Once extends Filter { + protected Hashtable done; + + protected void doStart() { done = new Hashtable(); } + protected boolean check() { return done.get(here.cell) == null; } + protected void accepted() { done.put(here.cell, here.cell); } + } + + + static public class Limited extends Filter { + protected int n, donenum; + +// public Limited(Any iter, int n) { this.iter = iter; this.n = n; } + protected void doStart() { donenum = 0; } + protected boolean check() { + if(donenum > n*n*2) return false; + return iter.here.nth < n; + } + protected void accepted() { donenum++; } + } +} \ No newline at end of file diff --git a/Modules/iter/README b/Modules/iter/README new file mode 100644 index 0000000..ee62007 --- /dev/null +++ b/Modules/iter/README @@ -0,0 +1 @@ +Some experiments for advanced ways of iteration through the structure. diff --git a/Modules/joystick/LinuxJoystick.java b/Modules/joystick/LinuxJoystick.java new file mode 100644 index 0000000..95ce586 --- /dev/null +++ b/Modules/joystick/LinuxJoystick.java @@ -0,0 +1,91 @@ +/* +ZZMbox.java + * + * Copyright (c) 2000, Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.io.*; + +/** A simple class to use the Linux joystick API. + * A separate thread is used to read in the blocking mode from the + * joystick and the appropriate callbacks are made. + */ + +public class LinuxJoystick implements Runnable { +public static final String rcsid = "$Id: LinuxJoystick.java,v 1.3 2000/09/19 10:32:03 ajk Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + FileInputStream in; + Thread t = new Thread(this); + + public LinuxJoystick(File f) { + try { + in = new FileInputStream(f); + t.start(); + } catch(Exception e) { + throw new Error("Couldn't open joystick"); + } + } + + public synchronized void run() { + try { + byte[] bpacket = new byte[8]; + int[] packet = new int[8]; + while(true) { + int n = in.read(bpacket); + p("Read "+n); + for(int i=0; i<8; i++) { + packet[i] = bpacket[i]; + if(packet[i] < 0) packet[i] += 256; + } + p("R: "+ + packet[0]+" "+ + packet[1]+" "+ + packet[2]+" "+ + packet[3]+" "+ + packet[4]+" "+ + packet[5]+" "+ + packet[6]+" "+ + packet[7]); + + long ms = packet[0] + (packet[1]<<8) + (packet[2]<<16) + + (packet[3]<<24); + int value = packet[4]+((packet[5]&0x7F)<<8); + if((packet[5]&0x80)!=0) + value -= 32768; + int type = packet[6]; + int num = packet[7]; + + p("EV: "+ms+" "+value+" "+type+" "+num); + } + } catch(Exception e) { + throw new Error("Couldn't open joystick"); + } + } + + /** For testing. */ + static public void main(String argv[]) { + LinuxJoystick j = new LinuxJoystick(new File("/dev/js0")); + } + +} diff --git a/Modules/mbox/SingleMail.zob b/Modules/mbox/SingleMail.zob new file mode 100644 index 0000000..3bb5db4 --- /dev/null +++ b/Modules/mbox/SingleMail.zob @@ -0,0 +1,133 @@ +/* +SingleMail.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + */ + +package org.gzigzag.module.mbox; + +import org.gzigzag.*; +import java.awt.*; + + + +/** A presentation of a single e-mail message. + */ + +public class SingleMail implements FlobView, ZOb { + public static final boolean dbg = true; + static final void p(String s) { if (dbg) System.out.println(s); } + + STRUCTPARAMS { + Font hfont = new Font("SansSerif", Font.PLAIN, 14); + Font dfont = new Font("SansSerif", Font.BOLD, 14); + Font bfont = new Font("Monospaced", Font.PLAIN, 12); + + int tabstop = 8; + } + + int headerh; + int bodyh; + FontMetrics hfm; + Color headerc, datac, bodyc; + String tabs[]; + + INITIALIZE { + headerh = (hfont.getSize() > dfont.getSize()? hfont.getSize() + : dfont.getSize()); + bodyh = bfont.getSize(); + hfm = FONTMETRICS(hfont); + headerc = datac = bodyc = Color.red; + + tabs = new String[tabstop + 1]; + tabs[0] = ""; + for (int i = 1; i < tabstop + 1; i++) + tabs[i] = tabs[i - 1] + '\t'; + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[]dims, ZZCell accursed) { + Dimension d = into.getSize(); + + ZZCell handle = accursed.h("d.ref", -1); + + ZZCell c = handle; + ZZCell f; + int y = 0; + c = c.s("d.handle", 1); + while (c != null && y <= d.height) { + f = c.s("d.1", 1); + if (f != null) // Header record + y = addHeader(into, y, c, f); + else + y = addBody(into, y, c); + c = c.s("d.handle", 1); + } + } + + int addHeader(FlobSet into, int y, ZZCell c, ZZCell d) { + p(into.toString() + y + c.toString() + d.toString()); + p("C: " + c.getID()); + p("D: " + d.getID()); + String field = c.getText(); + String data = d.getText(); + y += headerh; + into.add(new TextDecor(0, y, field, headerc, hfont)); + into.add(new TextDecor(hfm.stringWidth(field) + 10, y, + data, datac, dfont)); + return y; + } + + int addBody(FlobSet into, int y, ZZCell c) { + String body = c.getText(); + int start = 0; + int end = -1; + while (end < body.length()) { // Split into lines + end = body.indexOf('\n', end + 1); + if (end == -1) + end = body.length(); + y += bodyh; + if (start < end) { + String line = body.substring(start, end); + StringBuffer buf = new StringBuffer(); + int offs = 0; + int pos = 0; + int tab = -1; + while (tab < line.length()) { // Expand tabs + tab = line.indexOf('\t', tab + 1); + if (tab == -1) + tab = line.length(); + buf.append(line.substring(pos, tab)); + if (tab < line.length()) { + int tablen = tabstop - ((tab + offs) % tabstop); + p("Tab: " + tablen); + buf.append(tabs[tablen]); + offs = offs + tablen - 1; + } + pos = tab + 1; + } + into.add(new TextDecor(0, y, new String(buf), bodyc, bfont)); + } + start = end + 1; + } + return y; + } +} + + +// vim: set syntax=java : diff --git a/Modules/mbox/ZZDateParser.java b/Modules/mbox/ZZDateParser.java new file mode 100644 index 0000000..fc43c6a --- /dev/null +++ b/Modules/mbox/ZZDateParser.java @@ -0,0 +1,398 @@ +/** + * ZZDateParser.java + * Created: Wed Feb 9 08:20:13 2000 + * + * + * Copyright (c) 1999, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + * + * @author Vesa Parkkinen + * @version 0.2 ( might even work, sometimes ) + * + */ + +package org.gzigzag.module; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.StringTokenizer; +import java.util.TimeZone; +import java.util.SimpleTimeZone; + +/** + * This class tries to parse RFC 822 formatted dates. + * I haven't yet seen the spec, but this seems to work with + * few strings taken from my mails. + * OK, now that i've seen the spec, this should pretty much be capable + * of parsing the dates. + * Except the zone name information is not used. + *

    + */ +public class ZZDateParser { +public static final String rcsid = "$Id: ZZDateParser.java,v 1.9 2000/09/19 10:32:03 ajk Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + /** + * Month names used in date string. + */ + static String[] months = { "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" }; + + static String[] days = { "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun" }; + + /** + * Method for parsing RFC 822 formatted dates to calendar objects. + * @param String d Date string in RFC 822 format. + * @return Calendar calendar having the date and time from RFC 822 + * ERROR CHECKING IS MISSING ! + * Will be added someday soon. + */ + public static Calendar parse(String d){ + + int year = 1; + int month = 1; + int date = 1; + + String day; + + int time[]; + + int gmt_diff[]; + + d.trim(); + try{ + + /* check whether we have day name */ + StringTokenizer t = new StringTokenizer( d, " " ); + + //if ( t.countTokens() > 1 ){ + //day = t.nextToken(); + // t.nextToken( " " ); + //} + //String tok; + try { + day = t.nextToken( ); + date = (int) Integer.parseInt( day ); + } catch( NumberFormatException nfe ) { + //day = t.nextToken(); + //t.nextToken( ); + date = (int) Integer.parseInt( t.nextToken( ) ); + } + //try{ + String smonth = t.nextToken(); + + for ( int i = 0; i < 12 ; i++ ) + if( smonth.equals( months[ i ] ) ){ + month = i ; + break; + } + + year = (int) Integer.parseInt( t.nextToken() ); + + time = parseTime( t.nextToken() ); + + String[] id; + + String s; + + + int off = 0; + + if( t.hasMoreTokens() ) + gmt_diff = parseTz(t.nextToken()); + + //if( ! t.hasMoreTokens() ){ + if( t.hasMoreTokens() ){ + gmt_diff = parseTz(t.nextToken()); + + off = gmt_diff[0] * 60 * 60 * 1000 + gmt_diff[1] * 60 * 1000; + id = TimeZone.getAvailableIDs( off ); + if ( id.length > 0 ) + s = id[0]; + else s = ""; + } else { + + s = "GMT";//t.nextToken(); + + } + + Calendar + calendar = new GregorianCalendar( + new SimpleTimeZone( off, s ) ); + + calendar.set( year, month, date, + time[0], time[1], time[2] ); + + return calendar;} + catch (Exception e){ + pa("Not a rfc822 date! Fix it :" + e); + return new GregorianCalendar(); + } + } + + /** + * What we've got here is a method to parse + * Calendar to RFC 822 formatted date String. + * + * @param Calendar calendar having the date and time from RFC 822 + * @return String d Date string in RFC 822 format. + * + */ + public static String parse(Calendar c){ + String dateString = ""; + + /* parse day string */ + int d = c.get(Calendar.DAY_OF_WEEK); + + String day = ""; + + switch ( d ){ + case (Calendar.MONDAY): + day = days[0]; + break; + + case (Calendar.TUESDAY): + day = days[1]; + break; + + case (Calendar.WEDNESDAY): + day = days[2]; + break; + + case (Calendar.THURSDAY): + day = days[3];; + break; + + case (Calendar.FRIDAY): + day = days[4];; + break; + + case (Calendar.SATURDAY): + day = days[5];; + break; + + case (Calendar.SUNDAY): + day = days[6];; + break; + + default: + day = ""; + break; + } + //*/ + //day = days[d]; + if ( day.length() == 3 ) + dateString += day +", "; + + int dm = c.get(Calendar.DAY_OF_MONTH); + + if( dm < 1 || dm > 31 ) dm = 1; + + dateString += "" + dm + " " ; + + int m = c.get(Calendar.MONTH); + + String month = ""; + /* + switch ( m ){ + case (Calendar.JANUARY): + month = months[0]; + break; + case (Calendar.FEBRUARY): + month = months[1]; + break; + case (Calendar.MARCH): + month = months[2]; + break; + case (Calendar.APRIL): + month = months[3]; + break; + case (Calendar.MAY): + month = months[4]; + break; + case (Calendar.JUNE): + month = months[5]; + break; + case (Calendar.JULY): + month = months[6]; + break; + case (Calendar.AUGUST): + month = months[7]; + break; + case (Calendar.SEPTEMBER): + month = months[8]; + break; + case (Calendar.OCTOBER): + month = months[9]; + break; + case (Calendar.NOVEMBER): + month = months[10]; + break; + case (Calendar.DECEMBER): + month = months[11]; + break; + default: + month = months[0]; + } + */ + + month = months[m]; + + dateString += month + " "; + + int hour = c.get(Calendar.HOUR_OF_DAY); + + String hh = ""+ hour; + + hh = addZeros(hh,2); + + int min = c.get(Calendar.MINUTE); + + String mm = ""+ min; + + mm = addZeros(mm,2); + + int sec = c.get(Calendar.SECOND); + + String ss = ""+ sec; + + ss = addZeros(ss,2); + + dateString += hh +":" + mm + ":" + ss + " " ; + + // tz + + int tz = c.get(Calendar.ZONE_OFFSET); + + int tz_h = tz / ( 60 * 60 * 1000 ); + int tz_m = ( tz % ( 60 * 60 * 1000 ) ) / 60 * 1000; + String t = addZeros("" + Math.abs(tz_h), 2); + t += addZeros("" + tz_m, 2); + if( tz_h < 0 ) + dateString += "-"; + if( tz_h == 0 && tz_m == 0 ) + dateString += "GMT"; + else dateString += ""+ t; + + return dateString; + + } + + private static String addZeros(String s,int count){ + int l = s.length(); + if ( l < count ) + for ( int i = l; i < count;i++){ + s = "0" + s;} + return s; + } + + + private static int[] parseTime( String time ){ + + int[] comp = { 0, 0, 0 }; + + StringTokenizer tt = new StringTokenizer(time,":"); + + if( tt.hasMoreTokens() ) + comp[0] = (int)Integer.parseInt(tt.nextToken()); + else return comp; + + if( tt.hasMoreTokens() ) + comp[1] = (int)Integer.parseInt(tt.nextToken()); + else return comp; + + if( tt.hasMoreTokens() ) + comp[2] = (int)Integer.parseInt(tt.nextToken()); + + return comp; + } + + /* XXX TODO: add parsing of zone names if needed. */ + private static int[] parseTz( String tz ){ + + int[] comp = { 0, 0 }; + + int negative = 1; + + tz.trim(); + + if( tz.startsWith( "-" ) ){ + negative = -1; + } + + int l = tz.length(); + + String s; + + StringTokenizer tt = new StringTokenizer( tz.substring( 1, l ) ); + + if ( tt.hasMoreTokens() ) + s = tt.nextToken(); + else s = tz.substring( 1, l ); + + int aa; + + try { + aa = (int) Integer.parseInt( s ); + } + catch( Exception e ) { + return comp; + } + + comp[0] = negative * (int) aa / 100; + // do we need this + comp[1] =/* negative * */ (int) aa % 100; + + return comp; + + } + + /* + public static void main(String[] argv){ + //Calendar c = ZZDateParser.parse("Tue, 15 Feb 2000 23:57:42 GMT"); + Calendar c = ZZDateParser.parse("Mon, 14 Feb 2000 18:04 -0200"); + //Calendar c = ZZDateParser.parse("Sun, 13 Feb 2000 18:04:26 -0200"); + //System.out.println(c.toString()); + //System.out.println(c.getTime().getTime()); + //System.out.println(c.get(Calendar.DATE)); + //System.out.println(c.get(Calendar.MONTH)); + //System.out.println("ZONE_OFFSET: " + // + (c.get(Calendar.ZONE_OFFSET))); // in hours + //System.out.println("DST_OFFSET: " + // + (c.get(Calendar.DST_OFFSET))); // in hours + + System.out.println("***********************"); + System.out.println(parse(c)); + }*/ +} diff --git a/Modules/mbox/ZZMbox.java b/Modules/mbox/ZZMbox.java new file mode 100644 index 0000000..efa509e --- /dev/null +++ b/Modules/mbox/ZZMbox.java @@ -0,0 +1,742 @@ +/* +ZZMbox.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka and Vesa Parkkinen + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.text.*; // DateFormat +import java.io.*; +import java.awt.*; +import gnu.regexp.*; + +/** A mailbox file reader. + *

    + * AAAAAAAARGGGGGGGGGGHHHHH!!!!!! How to do 8-bit cleanliness and + * internationalization correctly? It's still just a stream of bytes + * that we have underneath. Should probably use encoding when converting + * bytescroll stuff to strings. Gnnnh... + *

    + * The way to test this is: + *

    • Put a path to the mbox to a cell, put right-hand cursor in it and + * execute ZZMbox.READMBOX + *
    + *

    + * TODO:

    • put all headers somewhere (sorted)
    • + *
    • more ways to connect messages (references?)
    • + *
    • smart way to move in threads
    • + *
    + */ + +public class ZZMbox { +public static final String rcsid = "$Id: ZZMbox.java,v 1.32 2000/11/06 12:06:17 ajk Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + static final void pa(String s) { ZZLogger.log(s); } + + static ZZCell byDate; + static ZZCell bySender; + static ZZCell bySubject; + static ZZCell byId; + + static Hashtable hash = new Hashtable(); + + static public ZZModule module = new ZZModule() { + public void action(String id, ZZCell code, + ZZCell target, + ZZView v, ZZView cv, + String key, Point pt, + ZZScene xi) { + try { + + ZZCell viewCell = v.getViewcell(); + ZZCell viewCursor = ZZCursorReal.get(viewCell); + + p("ZZMbox ACTION!"); + + if(id.equals("CREATEFLOBWINDOW")) { + // paths are: + // + // Date: + // handle -> Date: (d.handle) + // headcell(d.clone, -1) + // d.order +1 + // + // From: same + // Subject: same + + String[] fields = new String[] { + "Subject", "From", "Date", "ARDate" + }; + ZZCell mli = viewCell.getHomeCell().N("d.2", 1); + mli.setText("MailflobDims"); + + ZZCell dlc = mli.N("d.1", 1); + ZZCell odlc = dlc; + + ZZCell[] flobdims = new ZZCell[fields.length]; + + for(int i=0; i= scr.curEnd()) { + i = (int)(scr.curEnd()-offs-1); + } + s = scr.getString(offs, i); + ind = s.indexOf('\n'); + } + if(ind<0 && offs != scr.curEnd()) { + p("Problem: no newline at end!"); + //return null; + s = scr.getString(offs, (int)scr.curEnd()); + offs = scr.curEnd(); + return s; + + } + + s = s.substring(0, ind); // nl not included + offs += ind+1; + return s; + } + + long hlstart; + long hlend; + + String getHdrLine() throws Exception { + //p("Gethdrline"); + hlstart = offs; + long o0 = offs; + String s = getLine(); + if(s.equals("")) { // Start of body + return null; + } + if(startws==null) + startws = new RE("^\\s"); + if(startws.getMatch(s, 0, RE.REG_ANCHORINDEX)!=null) { + throw new ZZError("ARGH! Invalid header"); + } + + while(true) { + o0 = offs; + String extra = getLine(); + if(startws.getMatch(extra, 0, RE.REG_ANCHORINDEX) + == null) break; + s += extra; + p("Hdrline reloop "+extra); + } + //p("Hdrline end "+s); + offs = o0; + hlend = offs-2; + return s; + } + boolean was_empty = false; + String getBodyLine() throws Exception { + p("Getbody"); + long o0 = offs; + String s = getLine(); + if( s == null ) return null; + if(startfrom==null) + startfrom = + new RE("^From (.+) (... ... .. ..:..:.. ....)(.*)"); + if(startfrom.getMatch(s, 0, RE.REG_ANCHORINDEX)!=null && + was_empty) { + p("GETBODY: END BODY " + s); + offs = o0; + return null; + } + p("GETBODYRET: "+s); + if ( s.equals("")){ + was_empty = true; + } else { + was_empty = false; + } + return s; + } + + Span sp(long offs, REMatch m, int i) { + return sp(offs, m.getSubStartIndex(i), + m.getSubEndIndex(i)); + } + Span sp(long offs, long i1, long i2) { + return sp(i1+offs, i2+offs); + } + Span sp(long i1, long i2) { + return Span.create(Address.scrollOffs(scr, i1), + Address.scrollOffs(scr, i2)); + } + + void dohoriz(ZZCell c, long o, REMatch m, int n) { + for(int i=1; i\n"); + writer.write("\n"); + writer.write(target.getText()+"\n"); + writer.write("\n"); + writer.write("\n"); + + writer.write("

    " + target.getText() + "

    \n"); + + if (target.s("d.1", 1) != null) { + writer.write("\n"); + printHtmlTree("d.2", "d.1", "d.clone", target.s("d.1", 1), + writer, 1, 10, 2); + writer.write("\n"); + } + + writer.write("\n"); + writer.write("\n"); + writer.close(); + } else { + pa("UNKNOWN Mind COMMAND "+id); + } + } catch(Exception e) { + e.printStackTrace(); + throw new ZZError(""+e); + } + } + + }; + private static void printTextTree(String dim, String dimTop, ZZCell accursed, + BufferedWriter writer, int start, int end) { + + Vector cells = getAllCells(dim, accursed); + int i = 0; + try { + + while (i < cells.size()) { + if (!((ZZCell)cells.elementAt(i)).getText().equals("")) { + writer.write(/*"
  • "+*/((ZZCell)cells.elementAt(i)).getText()+"\n"); + } + if (((ZZCell)cells.elementAt(i)).s(dimTop, 1) != null) { + for (int j=0; j topics) writer.write("
      \n"); + while (i < cells.size()) { + if (!((ZZCell)cells.elementAt(i)).getText().equals("")) { + if (start > topics) { + writer.write("
    • "); + if (((ZZCell)cells.elementAt(i)).s(dimLink, -1) == null) { + if (((ZZCell)cells.elementAt(i)).s(dimLink, 1) != null) + writer.write(""); + writer.write(((ZZCell)cells.elementAt(i)).getText()); + } else { + writer.write(""); + writer.write(((ZZCell)cells.elementAt(i)).getText()+""); + } + writer.write("\n"); + } else { + writer.write(""); + if (((ZZCell)cells.elementAt(i)).s(dimLink, -1) == null) { + if (((ZZCell)cells.elementAt(i)).s(dimLink, 1) != null) + writer.write(""); + writer.write(((ZZCell)cells.elementAt(i)).getText()); + } else { + writer.write(""); + writer.write(((ZZCell)cells.elementAt(i)).getText()+""); + } + writer.write("\n"); + } + } + if (((ZZCell)cells.elementAt(i)).s(dimTop, 1) != null) { + writer.write("\n"); + if(start < end) printHtmlTree(dim, dimTop, dimLink, ((ZZCell)cells.elementAt(i)).s(dimTop, 1), writer, + start + 1, end, topics); + writer.write("\n"); + } + i++; + } + if (start > topics) writer.write("
    \n"); + } catch (IOException iOE) {} + } + + + + private static Vector getAllCells(String dim, ZZCell accursed) { + int LIMIT = 1000; + Vector cells = new Vector(); + ZZCell next = null; + + cells.addElement(accursed); + + int i = 1; + while (cells.size() < LIMIT ) { + next = accursed.s(dim, i++); + if(next != null && !cells.contains(next)) cells.addElement(next); + else break; + } + return cells; + } +} diff --git a/Modules/mind/MindSun.java b/Modules/mind/MindSun.java new file mode 100644 index 0000000..ac7a473 --- /dev/null +++ b/Modules/mind/MindSun.java @@ -0,0 +1,398 @@ +/* + * MindSun.java + * + * A View for GZZ 0.6.X. + * + * @author asko.soukka@iki.fi + * @version 0.1 + * + * I was not satisfied with MindSundiew view. It wasted too much space + * and still did not show enough information. So, I dropped using full circles. + * Still this view is optimized for cyclic structures. + * + * Copyright (c) 2002 Asko Soukka + * Contains a few parts of CompassView.java (c) 2002 Tuukka Hastrup + * GZigZag is written by Tuomas Lukka + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * See the LICENSE.lgpl for the specific terms of the license. + * + * This library 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 + * Library General Public License for more details. + */ +/* +To do: + +Commenting code :) (javadoc-spesific) + +*/ + + +package org.gzigzag.module; + +import org.gzigzag.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.lang.Math; +import java.util.Vector; + +class MindSun implements FlobView, ZOb { + + /** */ + public static final String rcsid = "$Id: MindSun.java,v 1.1.2.3 2002/02/16 16:33:06 tuukkah Exp $"; + + public MindSun() {} + + /** + * @param + */ + public String readParams(ZZCell c) { return null; }; + + /** + * @param + * @param + * @param + * @param + * @param + */ + public void raster(FlobSet into, FlobFactory fact, ZZCell view, + String[] dims, ZZCell accursed) { + + /** */ + Dimension d = into.getSize(); + int midx = d.width / 2; + int midy = d.height / 2; + int r = d.width / 5; + + /** */ + ZZUtil.showFlobDims(into, fact, view, 3); + + /** */ + Vector cells = getAllCells(dims[1], accursed); + if (cells.size() > 0) { + drawCircle(midx, midy, into, fact, dims[1], cells, r, 1, false); + drawTopCurves(midx, midy, into, fact, dims, cells, r, 1.95 * Math.PI, 2, 4, true); + drawSubCurves(midx, midy, into, fact, dims, cells, r, 0.95 * Math.PI, 2.95 * Math.PI, 2, 3, true); + + /** */ + Dimension c = fact.getSize(null, 1); + int cw = c.width; + int ch = c.height; + + for (int i = 1; i < 4; i++) { + if (accursed.s(dims[2], -i) != null) { + fact.makeFlob(into, accursed.s(dims[2], -i), accursed.s(dims[2], -i), + (float)0.75, midx + x(1.95 * Math.PI, r)-cw/2, midy+y(1.95 * Math.PI, r)-ch/2*(i+1), i+1, + (int)(cw * 0.75), (int)(ch * 0.75)); + } + if (accursed.s(dims[2], i) != null) { + fact.makeFlob(into, accursed.s(dims[2], i), accursed.s(dims[2], i), + (float)0.75, midx + x(1.95 * Math.PI, r)-cw/2, midy+y(1.95 * Math.PI, r)-ch/3+ch/2*i, i+1, + (int)(cw * 0.75), (int)(ch * 0.75)); + } + } + } + } + + /** + * @param + * @param + */ + private Vector getAllCells(String dim, ZZCell accursed) { + /** */ + int LIMIT = 20; + + /** */ + Vector cells = new Vector(); + + /** */ + ZZCell next = null; + + /** */ + cells.addElement(accursed); + + /** */ + int i = 1; + do { + if (cells.size() > LIMIT / 2) break; + next = accursed.s(dim, i++); + if(next != null && !cells.contains(next)) cells.addElement(next); + else break; + } while (true); + + /** */ + i = -1; + do { + if (i < -LIMIT / 2) break; + next = accursed.s(dim, i--); + } while (next != null && !cells.contains(next)); + + /** */ + if (next != accursed) { + i += 2; + do { + if (cells.size() > LIMIT) break; + next = accursed.s(dim, i++); + if(next != null && !cells.contains(next)) cells.addElement(next); + else break; + } while (true); + } + + /** */ + return cells; + } + + /** + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ + private void drawTopCurves(int midx, int midy, FlobSet into, FlobFactory fact, String[] dims, Vector cells, + int r, double angle, int startLevel, int endLevel, boolean vanishing) { + /** */ + float factor = (float) (-Math.log(startLevel) / (-Math.log(startLevel)+2.7) + 1); + + /** */ + double angleStep = 2 * Math.PI / cells.size(); + + /** */ + for (int i=0; i= endAngle - angleStep / 3 * 2 + || cells.size()%2 != 0 && angle >= endAngle) + angle = (startAngle + (endAngle - startAngle) / 2) - (cells.size() - (i + 1)) * angleStep; + } + + /** */ + if (backup != null) cells.insertElementAt(backup, 0); + } + + /** + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ + private void drawCurve(int midx, int midy, FlobSet into, FlobFactory fact, Vector cells, + double startAngle, double endAngle, int r, int level, boolean vanishing) { + + /** */ + Dimension c = fact.getSize(null, 1); + int cw = c.width; + int ch = c.height; + + /** */ + double angle = startAngle + (endAngle - startAngle) / 2; + + /** */ + int i = 0; + ZZCell backup = null; + + /** */ + if (cells.elementAt(0) != null && ((ZZCell)cells.elementAt(0)).getText().equals("")) { + int dx = x(angle, r-cw/8); + int dy = y(angle, r-cw/8); + float factor = (float)-Math.log(level)/4+1; + fact.makeFlob(into, (ZZCell)cells.elementAt(i), (ZZCell)cells.elementAt(i), + factor, midx + dx-cw/2, midy+dy-ch/2, level+2, (int)(cw * factor), (int)(ch * factor)); + backup = (ZZCell)cells.elementAt(0); + cells.removeElementAt(0); + } + + /** */ + double angleStep; + if (cells.size()%2 == 0) angleStep = (endAngle - startAngle) / (cells.size() + 1); + else angleStep = (endAngle - startAngle) / cells.size(); + + /** */ + while (i < cells.size()) { + int dx = x(angle, r); + int dy = y(angle, r); + + /** */ + float factor; + if (i == 0) factor = (float)(-Math.log(level)/4+1.1); + else factor = (float)-Math.log(level)/4+1; + + if(cells.elementAt(i) != null) + fact.makeFlob(into, (ZZCell)cells.elementAt(i), (ZZCell)cells.elementAt(i), + factor, midx + dx-cw/2, midy+dy-ch/2, level, (int)(cw * factor), (int)(ch * factor)); + + /** */ + if (vanishing) { + if (i < cells.size() / 2) level ++; + else if (i > cells.size() / 2) level --; + } + i++; + + /** */ + angle += angleStep; + if (cells.size()%2 == 0 && angle >= endAngle - angleStep / 3 * 2 + || cells.size()%2 != 0 && angle >= endAngle) + angle = (startAngle + (endAngle - startAngle) / 2) - (cells.size() - i) * angleStep; + } + + /** */ + if (backup != null) cells.insertElementAt(backup, 0); + } + + /** + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ + private void drawCircle(int midx, int midy, FlobSet into, FlobFactory fact, String dim, Vector cells, + int r, int level, boolean vanishing) { + + /** */ + LineDecor.Builder line = new LineDecor.Builder(into, Color.red); + line.startl(4, 1); + + /** */ + Dimension c = fact.getSize(null, 1); + int cw = c.width; + int ch = c.height; + + /** */ + double angleStep = 2 * Math.PI / cells.size(); + double angle = (double) 1.95 * Math.PI; + + /** */ + int i = 0; + while (i < cells.size()) { + int dx = x(angle, r); + int dy = y(angle, r); + + /** */ + float factor = (float)-Math.log(level)/4+1; + + if(cells.elementAt(i) != null) +/* fact.centerFlob(into, (ZZCell)cells.elementAt(i), (ZZCell)cells.elementAt(i), + factor, new Point(midx + dx-cw/2, midy+dy-ch/2), 0, 0, level);*/ + fact.makeFlob(into, (ZZCell)cells.elementAt(i), (ZZCell)cells.elementAt(i), + factor, midx + dx-cw/2, midy+dy-ch/2, level, (int)(cw * factor), (int)(ch * factor)); + + /** */ + if (vanishing) { + if (i < cells.size() / 2) level ++; + else if (i > cells.size() / 2) level --; + } + /** */ + angle += angleStep; + + /** */ + if (cells.elementAt(i)!=null && cells.size() > 1) { + if (((ZZCell)cells.elementAt(i)).s(dim, 1) == null) { + line.l(midx+x(angle - angleStep / 2 - 0.01, r-ch)-cw/2, midy+y(angle - angleStep / 2 - 0.01, r-ch)-ch/2, + midx+x(angle - angleStep / 2 - 0.01, r+ch)-cw/2, midy+y(angle - angleStep / 2 - 0.01, r+ch)-ch/2); + line.l(midx+x(angle - angleStep / 2 + 0.01, r-ch)-cw/2, midy+y(angle - angleStep / 2 + 0.01, r-ch)-ch/2, + midx+x(angle - angleStep / 2 + 0.01, r+ch)-cw/2, midy+y(angle - angleStep / 2 + 0.01, r+ch)-ch/2); + } + else if (i < cells.size() - 1) { + if (((ZZCell)cells.elementAt(i)).s(dim, 1) != (ZZCell)cells.elementAt(i+1)) + line.l(midx+x(angle - angleStep / 2, r-ch)-cw/2, midy+y(angle - angleStep / 2, r-ch)-ch/2, + midx+x(angle - angleStep / 2, r+ch)-cw/2, midy+y(angle - angleStep / 2, r+ch)-ch/2); + } else { + if (((ZZCell)cells.elementAt(i)).s(dim, 1) != (ZZCell)cells.elementAt(0)) { + line.l(midx+x(angle - angleStep / 2, r-ch)-cw/2, midy+y(angle - angleStep / 2, r-ch)-ch/2, + midx+x(angle - angleStep / 2, r+ch)-cw/2, midy+y(angle - angleStep / 2, r+ch)-ch/2); + line.l(midx+x(angle - angleStep / 2 + 0.01, r-ch)-cw/2, midy+y(angle - angleStep / 2 + 0.01, r-ch)-ch/2, + midx+x(angle - angleStep / 2 + 0.01, r+ch)-cw/2, midy+y(angle - angleStep / 2 + 0.01, r+ch)-ch/2); + } + } + } + /** */ + i++; + } + + /** */ + line.endl(); + } + + protected int x(double angle, int length) { + return (int)(Math.cos(angle) * length); + } + + protected int y(double angle, int length) { + return (int)(Math.sin(angle) * length); + } +} diff --git a/Modules/mind/MindSundew.java b/Modules/mind/MindSundew.java new file mode 100644 index 0000000..0091aec --- /dev/null +++ b/Modules/mind/MindSundew.java @@ -0,0 +1,247 @@ +/* + * MindSundew.java + * + * Ajatuskihokkipurkkaviritys GZZ 0.6.X:lle. + * Mindmap scribble for GZigZag 0.6.X. + * + * @author asko.soukka@iki.fi + * + * Copyright (C) 2001 Asko Soukka, based on CompassView.java by Tuukka Hastrup + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * See the LICENSE.lgpl for the specific terms of the license. + * + * This library 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 + * Library General Public License for more details. + */ + +package org.gzigzag.module; + +import org.gzigzag.*; +import java.awt.Dimension; +import java.lang.Math; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.util.Vector; + +class MindSundew implements FlobView, ZOb { + + public static final String rcsid = "$Id: MindSundew.java,v 1.1.2.1 2002/02/16 15:19:25 tuukkah Exp $"; + private int level = 0; + private int levelA = 0; + private int levelB = 0; + + public MindSundew() {} + public String readParams(ZZCell c) { return null; }; + + public void raster(FlobSet into, FlobFactory fact, ZZCell view, + String[] dims, ZZCell accursed) { + + /* ---- alustetaan kaikenlaista ---- */ +// FlobDecorator linker = new StdLinks(); + ZZCell stdim = ZZCursorReal.get(view.s("d.dims", 1)); + + Dimension d = into.getSize(); + int midx = d.width / 2; + int midy = d.height / 2; + Dimension c = fact.getSize(null, 1); + int cw = c.width; + int ch = c.height; + + ZZUtil.showFlobDims(into, fact, view, 3); + /* ---------------------------------------------------- */ + + /* ---- piirretään ulottuvuuksien värit ylänurkkaan ---- */ + LineDecor.Builder line1 = new LineDecor.Builder(into, Color.black); + LineDecor.Builder line2 = new LineDecor.Builder(into, Color.gray); + LineDecor.Builder line3 = new LineDecor.Builder(into, Color.yellow); + + line1.startl(4, 1); + line2.startl(4, 1); + line3.startl(4, 1); + + line1.l(c.width/2, c.height/2, c.width*2, c.height/2); + line2.l(c.width/2, c.height/2, c.width/2, c.height*2); + line3.l(c.width/2, c.height/2, c.width*2, c.height*2); + + line1.endl(); + line2.endl(); + line3.endl(); + /* ---------------------------------------------------- */ + + /* ---- kutsutaan ensimmäistä piirtokierrosta ---- */ + drawLevel(into, fact, dims, accursed, d, c, stdim, midx, midy, cw, ch); + //linker.decorate(into, "", view); + /* ---------------------------------------------------- */ + + } + + private void drawLevel(FlobSet into, FlobFactory fact, String[] dims, ZZCell accursed, + Dimension d, Dimension c, ZZCell stdim, int midx, int midy, int cw, int ch) { + + /* ---- asetetaan piirtokierroksen tasokohtaiset ---- */ + level++; + float kerroin = 1; // käytetään solujen piirtokoossa + if (level > 1) { + kerroin = (float)0.7; + for (int i=2; i= this.x && hy >= this.y && hx < this.x+this.w + && hy < this.y+this.h) return handleCell; + return null; + } + }; + into.add(cf); + return cf; + } + + public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, int x, int y, int depth, float xfract, float yfract) + { + Dimension d = getSize(c, fract); + return makeFlob(into, c, handleCell, fract, + (int)(x-xfract*d.width), (int)(y-yfract*d.height), depth, d.width, d.height); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth, Dimension d) + { + if (d==null) d = getSize(c, fract); + int x, y; + x = p.x - d.height/2; y = p.y - d.height/2; + if (xalign<0) x = p.x; + if (xalign>0) x = p.x - d.width; + if (yalign<0) y = p.y; + if (yalign>0) y = p.y - d.height; + return makeFlob(into, c, handleCell, fract, x, y, depth, d.width, d.height); + } + + public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, int depth) + { + return centerFlob(into, c, handleCell, fract, p, xalign, yalign, depth, null); + } +} +// Local variables: +// tab-width: 4 +// End: diff --git a/Modules/multimedia/MediaFlobView.java b/Modules/multimedia/MediaFlobView.java new file mode 100644 index 0000000..e0c587d --- /dev/null +++ b/Modules/multimedia/MediaFlobView.java @@ -0,0 +1,40 @@ +/* +MediaFlobView.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.module.*; +import org.gzigzag.*; +import java.awt.*; + +public class MediaFlobView extends Default implements FlobView +{ + public static final String rcsid = "$Id: MediaFlobView.java,v 1.1 2001/03/05 08:44:14 deetsay Exp $"; + + private MediaFlobFactory mff = new MediaFlobFactory(); + + public void raster(FlobSet into, FlobFactory fact, ZZCell view, java.lang.String[] dims, + ZZCell accursed) + { + mff.placeFlob(into, accursed, accursed, 1, 0, 0, 1, 0, 0); + } +} diff --git a/Modules/multimedia/MediaMath.java b/Modules/multimedia/MediaMath.java new file mode 100644 index 0000000..5ee6368 --- /dev/null +++ b/Modules/multimedia/MediaMath.java @@ -0,0 +1,460 @@ +/* +MediaMath.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +/** + * MediaMath is a collection of MediaZObs that do mathematical functions. + * If at all possible, in the future this should be done with some actual + * mathematical language designed for GZigZag... + */ + +public class MediaMath +{ + public static final String rcsid = "$Id: MediaMath.java,v 1.1 2001/03/05 08:44:14 deetsay Exp $"; + + public abstract class MathZOb extends MediaZOb + { + protected Pixels pix = null; + + protected Vector oldframes = new Vector(); + + /** + * The inputs for these are just lists of MediaZObs connected on d.2, + * unlike the normal way, which is a list of parameter names, which + * in turn are connected to ZObs on d.1........ + */ + protected Vector readInputPixels() + { + Vector v = new Vector(); + Pixels inpix; + ZZCell d = cell; + do + { + inpix = MediaZOb.newMediaZOb(d).getPixels(); + v.addElement(inpix); + d = d.s("d.2"); + } + while ((d != null) && (!d.equals(cell))); + return v; + } + + protected Vector readInputZObs() + { + Vector v = new Vector(); + MediaZOb mz; + ZZCell d = cell; + do + { + mz = MediaZOb.newMediaZOb(d); + v.addElement(mz); + d = d.s("d.2"); + } + while ((d != null) && (!d.equals(cell))); + return v; + } + + /** + * Allocate enough pixels to fit all inputs in their correct coordinate positions. + */ + protected void createPix(Vector inputs) + { + if (inputs.size() < 1) + { + pix = new Pixels(1, 1); + pix.getPixels()[0] = 0xff000000; + return; + } + + Pixels inpix = (Pixels)inputs.elementAt(0); + int w = inpix.getWidth(), h = inpix.getHeight(); + int x = inpix.getX(), y = inpix.getY(); + + for (int i=1; i (w + x)) + { + w = inpix.getWidth() + inpix.getX() - x; + } + if ((inpix.getHeight() + inpix.getY()) > (h + y)) + { + h = inpix.getHeight() + inpix.getY() - y; + } + } + if (pix == null) + { + pix = new Pixels(w, h); + } + else + { + pix.setSize(w, h); + } + pix.setX(x); + pix.setY(y); + } + } + + public class add extends MathZOb + { + public int getInt(int def) + { + Vector inputs = readInputZObs(); + if (inputs.size() < 1) return def; + int S = 0; + for (int i=0; i 0xff0000) r = 0xff0000; + g = (pp & 0xff00) + (ipp & 0xff00); + if (g > 0xff00) g = 0xff00; + b = (pp & 0xff) + (ipp & 0xff); + if (b > 0xff) b = 0xff; + p[pi++] = 0xff000000 | r | g | b; + } + pi += pix.getWidth() - inpix.getWidth(); + } + } + pix.setFrame(pix.getFrame()+1); + return pix; + } + } + + public class and extends MathZOb + { + public int getInt(int def) + { + Vector inputs = readInputZObs(); + if (inputs.size() < 1) return def; + int S = 0xffffffff; + for (int i=0; i> 12) & 0xff0) * ((ipp >> 12) & 0xff0)) & 0xff0000; + g = (((pp >> 8) & 0xff) * ((ipp >> 8) & 0xff)) & 0xff00; + b = ((pp & 0xff) * (ipp & 0xff)) >> 8; + p[pi++] = 0xff000000 | r | g | b; + } + pi += pix.getWidth() - inpix.getWidth(); + } + } + pix.setFrame(pix.getFrame()+1); + return pix; + } + } + + public class or extends MathZOb + { + public int getInt(int def) + { + Vector inputs = readInputZObs(); + if (inputs.size() < 1) return def; + int S = 0; + for (int i=0; i= 0) + { + mz = new image(); + mz.readParams(c); + return mz; + } + } + catch (Exception e) {} + + cc = c.s("d.1"); + + if (cc == null) return null; + + ZZCell macroCell = cc; + cc = macroCell.h("d.clone"); + if (macroCell.equals(cc)) macroCell = null; + + String t = cc.getText(); + int x; + + /* + * This is an unnecessary check just because + * you get some errors if you try newZOb() on an URL :-) + */ + if (t.indexOf("://") >= 0) return null; + + x = t.indexOf('.'); + if (x > 1) try + { + mz = (MediaZOb)ZZModule.getModule(t.substring(0, x)).newZOb(t.substring(x + 1)); + mz.readParams(cc.s("d.1")); + if (macroCell != null) mz.setMacro(macroCell); + return mz; + } + catch (Exception e) {} + + /* + * Mathematical functions are hidden inside MediaMath.. + */ + if (t.equals("+")) { mz = mediaMath.new add(); mz.readParams(cc.s("d.1")); return mz; } + if (t.equals("&")) { mz = mediaMath.new and(); mz.readParams(cc.s("d.1")); return mz; } + if (t.equals("*")) { mz = mediaMath.new mul(); mz.readParams(cc.s("d.1")); return mz; } + if (t.equals("|")) { mz = mediaMath.new or(); mz.readParams(cc.s("d.1")); return mz; } + if (t.equals("%")) { mz = mediaMath.new xor(); mz.readParams(cc.s("d.1")); return mz; } + + return null; + } + + static public MediaZOb newMediaZOb(ZZCell c) + { + MediaZOb mz = newMediaZObNoDefault(c); + if (mz == null) + { + mz = new Default(); + mz.readParams(c); + } + return mz; + } + + /** + * Find a parameter of this cell from the ZZ-structure, and + * return it as a MediaZOb. + * + * @param name is the name of the parameter that you hope to find. + */ + protected MediaZOb readParam(String name) + { + MediaZOb mz = null; + + if (cell == null) return nullZOb; + + mz = readParam(name, cell, null); + + return (mz == null ? nullZOb : mz); + } + + /** + * Recursive part of the previous method + */ + private MediaZOb readParam(String name, ZZCell key, ZZCell first) + { + if ((key == null) || key.equals(first)) return null; + + if (first == null) first = key; + + if ((name != null) && (name.equals(key.getText()))) + { + ZZCell value = key.s("d.1"); + + //------------------------------------------------- + // An acceptable way of passing macro parameters? + + if ((value != null) && (value.getText().equals("param"))) + { + MediaZOb mz = null; + ZZCell parname = value.s("d.1"); + if (parname != null) + { + if (callFrom != null) + mz = readParam(parname.getText(), callFrom.s("d.1"), null); + + if (mz == null) + mz = newMediaZOb(parname.s("d.1")); + + return mz; + } + } + //------------------------------------------------- + return newMediaZOb(value); + } + + return readParam(name, key.s("d.2"), first); + } + + /** + * Contents of cell as text. + * + * @param def Default value. + */ + public String getText(String def) + { + return (cell == null ? def : cell.getText()); + } + + /** + * Contents of cell as integer. + * + * @param def Default value. + */ + public int getInt(int def) + { + String t = getText(""); + // try to parse hex + try { if (t.substring(0, 2).equals("0x")) return Integer.parseInt(t.substring(2), 16); } + catch (Exception e) {} + // try to parse decimal + try { return Integer.parseInt(t); } catch (Exception e) {} + + return def; + } + + public abstract Pixels getPixels(); +} + +// Local variables: +// tab-width: 4 +// End: diff --git a/Modules/multimedia/Pixels.java b/Modules/multimedia/Pixels.java new file mode 100644 index 0000000..cf0fbfe --- /dev/null +++ b/Modules/multimedia/Pixels.java @@ -0,0 +1,163 @@ +/* +Pixels.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +/** + * The purpose of this class is to be the type of return value + * for MediaZOb's getPixels() method. + * + * @see MediaZOb + */ + +public class Pixels +{ + public static final String rcsid = "$Id: Pixels.java,v 1.2 2001/03/05 08:44:14 deetsay Exp $"; + + private int width, height, x, y; + private int allocatedSize; + private int pixels[]; + + private int frame = 0; + public int getFrame() { return frame; } + public void setFrame(int f) { frame = f; } + + public int getX() { return x; } + public int getY() { return y; } + public int getCenterX() { return x + (width >> 1); } + public int getCenterY() { return y + (height >> 1); } + + public void setX(int a) { x = a; } + public void setY(int a) { y = a; } + public void setCenterX(int a) { x = a - (width >> 1); } + public void setCenterY(int a) { y = a - (height >> 1); } + + public int getWidth() { return width; } + public int getHeight() { return height; } + + private void checkSize() + { + int newsize = width*height; + if (newsize > allocatedSize) + { + pixels = null; + allocatedSize = newsize; + pixels = new int[allocatedSize]; + } + } + public void setSize(int a, int b) + { + width = a; + height = b; + checkSize(); + } + public void setWidth(int a) + { + width = a; + checkSize(); + } + public void setHeight(int a) + { + height = a; + checkSize(); + } + public void setCenterWidth(int a) + { + x += ((width - a) >> 1); + width = a; + checkSize(); + } + public void setCenterHeight(int a) + { + y += ((height - a) >> 1); + height = a; + checkSize(); + } + + public int[] getPixels() { return pixels; } + + /** + * Thanks to this method there's no need to use MemoryImageSource + * to get an Image from pixel data. + */ + public ImageProducer getSource() + { + return new ImageProducer() + { + private Vector imageConsumers = new Vector(); + + public void addConsumer(ImageConsumer ic) + { + if ((ic != null) && (!isConsumer(ic))) + { + imageConsumers.addElement(ic); + } + } + public boolean isConsumer(ImageConsumer ic) + { + return imageConsumers.contains(ic); + } + public void removeConsumer(ImageConsumer ic) + { + imageConsumers.removeElement(ic); + } + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + public void startProduction(ImageConsumer ic) + { + addConsumer(ic); + + int i = 0; + ImageConsumer cons; + try + { + while (true) + { + cons = (ImageConsumer)imageConsumers.elementAt(i++); + cons.setDimensions(getWidth(), getHeight()); + cons.setHints(ImageConsumer.TOPDOWNLEFTRIGHT + | ImageConsumer.SINGLEFRAME | ImageConsumer.SINGLEPASS); + cons.setPixels(0, 0, getWidth(), getHeight(), ColorModel.getRGBdefault(), + getPixels(), 0, getWidth()); + cons.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + catch (Exception e) {} + } + }; + } + + public Pixels(int w, int h) + { + x = 0; + y = 0; + width = w; + height = h; + pixels = new int[width*height]; + } +} diff --git a/Modules/multimedia/PolygonRenderer.java b/Modules/multimedia/PolygonRenderer.java new file mode 100644 index 0000000..ea47248 --- /dev/null +++ b/Modules/multimedia/PolygonRenderer.java @@ -0,0 +1,61 @@ +/* +PolygonRenderer.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +/** + * unfinished.. + */ + +public class PolygonRenderer extends MediaZOb +{ + public static final String rcsid = "$Id: PolygonRenderer.java,v 1.1 2001/03/05 08:44:14 deetsay Exp $"; + + private Pixels pix; + + public Pixels getPixels() + { + int w = readParam("width").getInt(256); + int h = readParam("height").getInt(256); + if (pix == null) + { + pix = new Pixels(w, h); + } + else + { + pix.setSize(w, h); + } + int p[] = pix.getPixels(); + for (int i=0; i<(w*h); i++) p[i] = 0xff000000; + + /* sort polygons */ + + /* render */ + + return pix; + } +} diff --git a/Modules/multimedia/Polygons.java b/Modules/multimedia/Polygons.java new file mode 100644 index 0000000..3f01109 --- /dev/null +++ b/Modules/multimedia/Polygons.java @@ -0,0 +1,65 @@ +/* +Polygons.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +/** + * unfinished + */ + +public class Polygons +{ + public static final String rcsid = "$Id: Polygons.java,v 1.1 2001/03/05 08:44:14 deetsay Exp $"; + + public class PolyPoint + { + public int x, y, z; + public int tx, ty, ex, ey, bx, by; + } + + public class Polygon + { + public PolyPoint points[]; + + public Polygon() + { + points = new PolyPoint[3]; + } + } + + private PolyPoint points[]; + private Polygon polygons[]; + + public PolyPoint[] getPoints() { return points; } + public Polygon[] getPolygons() { return polygons; } + + public Polygons(int npoints, int npolygons) + { + points = new PolyPoint[npoints]; + polygons = new Polygon[npolygons]; + } +} diff --git a/Modules/multimedia/adjust.java b/Modules/multimedia/adjust.java new file mode 100644 index 0000000..14b5253 --- /dev/null +++ b/Modules/multimedia/adjust.java @@ -0,0 +1,109 @@ +/* +adjust.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +/** + * unfinished + */ + +public class adjust extends MediaZOb +{ + public static final String rcsid = "$Id: adjust.java,v 1.1 2001/03/05 08:44:14 deetsay Exp $"; + + private Pixels pix = null; + + private int oldframe=0, oldradj=0, oldgadj=0, oldbadj=0, oldhadj=0, oldsadj=0, oldbradj=0; + + public Pixels getPixels() + { + Pixels inpix = readParam("input").getPixels(); + + int radj = readParam("red").getInt(100); + int gadj = readParam("green").getInt(100); + int badj = readParam("blue").getInt(100); + + int hadj = readParam("hue").getInt(100); + int sadj = readParam("saturation").getInt(100); + int bradj = readParam("brightness").getInt(100); + + if (pix != null && inpix.getFrame() == oldframe + && radj == oldradj && gadj == oldgadj && badj == oldbadj + && hadj == oldhadj && sadj == oldsadj && bradj == oldbradj) + { + return pix; + } + oldradj = radj; oldgadj = gadj; oldbadj = badj; + oldhadj = hadj; oldsadj = sadj; oldbradj = bradj; + oldframe = inpix.getFrame(); + + int w = inpix.getWidth(); + int h = inpix.getHeight(); + int px = inpix.getX(); + int py = inpix.getY(); + + if (pix == null) + { + pix = new Pixels(w, h); + } + else + { + pix.setSize(w, h); + } + pix.setX(px); + pix.setY(py); + + float hsbvals[] = new float[3]; + int ip[] = inpix.getPixels(); + int pred, pgreen, pblue, prgb; + int op[] = pix.getPixels(); + for (int i=0; i<(w*h); i++) + { + prgb = ip[i]; + pred = ((prgb >> 16) & 0xff) * radj / 100; + pgreen = ((prgb >> 8) & 0xff) * gadj / 100; + pblue = (prgb & 0xff) * badj / 100; + + Color.RGBtoHSB( + (pred > 255 ? 255 : pred), + (pgreen > 255 ? 255 : pgreen), + (pblue > 255 ? 255 : pblue), + hsbvals); + + hsbvals[0] = hsbvals[0] * hadj / 100; + hsbvals[1] = hsbvals[1] * sadj / 100; + hsbvals[2] = hsbvals[2] * bradj / 100; + + op[i] = Color.HSBtoRGB( + (hsbvals[0] > 1 ? 1 : hsbvals[0]), + (hsbvals[1] > 1 ? 1 : hsbvals[1]), + (hsbvals[2] > 1 ? 1 : hsbvals[2])); + } + + return pix; + } +} diff --git a/Modules/multimedia/crop.java b/Modules/multimedia/crop.java new file mode 100644 index 0000000..95c93c6 --- /dev/null +++ b/Modules/multimedia/crop.java @@ -0,0 +1,94 @@ +/* +crop.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +/** + * unfinished + */ + +public class crop extends MediaZOb +{ + public static final String rcsid = "$Id: crop.java,v 1.2 2001/03/05 08:44:14 deetsay Exp $"; + + private Pixels pix = null; + + private int oldframe=0, oldpw=0, oldph=0, oldpx=0, oldpy=0; + + public Pixels getPixels() + { + Pixels inpix = readParam("input").getPixels(); + + int iw = inpix.getWidth(); + int ih = inpix.getHeight(); + int ix = inpix.getX(); + int iy = inpix.getY(); + + int pw = readParam("width").getInt(iw); + int ph = readParam("height").getInt(ih); + int px = readParam("x").getInt(ix); + int py = readParam("y").getInt(iy); + + if (pix != null && inpix.getFrame() == oldframe + && pw == oldpw && ph == oldph && px == oldpx && py == oldpy) + { + return pix; + } + oldpw = pw; oldph = ph; oldpx = px; oldpy = py; oldframe = inpix.getFrame(); + + if (pix == null) + { + pix = new Pixels(pw, ph); + } + else + { + pix.setSize(pw, ph); + } + pix.setX(px); + pix.setY(py); + + int p[] = pix.getPixels(), ip[] = inpix.getPixels(); + int i = 0; + for (int y=py; y= iy + ih)) + { + for (int x=0; x= ix + iw)) p[i++] = 0xff000000; + else p[i++] = ip[ ((y-iy)*iw)+(x-ix) ]; + } + } + } + pix.setFrame(pix.getFrame()+1); + return pix; + } +} diff --git a/Modules/multimedia/dots.java b/Modules/multimedia/dots.java new file mode 100644 index 0000000..6841e8b --- /dev/null +++ b/Modules/multimedia/dots.java @@ -0,0 +1,58 @@ +/* +dots.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +public class dots extends MediaZOb +{ + public static final String rcsid = "$Id: dots.java,v 1.2 2001/03/05 08:44:14 deetsay Exp $"; + + private Pixels pix = null; + + private void plot(int p[], int w, int h, int n) + { + + } + + public Pixels getPixels() + { + if (pix == null) + { + int w = readParam("width").getInt(64); + int h = readParam("height").getInt(64); + int c = readParam("bg").getInt(0); + pix = new Pixels(w, h); + int p[] = pix.getPixels(); + for (int i=0; i<(w*h); i++) + { + p[i] = 0xff000000 | c; + } + plot(p, w, h, readParam("dots").getInt(100)); + } + return pix; + } +} diff --git a/Modules/multimedia/image.java b/Modules/multimedia/image.java new file mode 100644 index 0000000..0d00a9f --- /dev/null +++ b/Modules/multimedia/image.java @@ -0,0 +1,102 @@ +/* +image.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; +import java.net.*; + +/** Image mediazob. + * Images can be read from a different place by setting the property images.from, + * like + * java -Dimages.from=img:///=file:///home/antkaij/cvs/gzigzag-demo/Java/demospace-lomat.2.zz/ org.gzigzag.Main demospace-lomat.2.zz + */ + +public class image extends MediaZOb +{ + public static final String rcsid = "$Id: image.java,v 1.7 2001/02/28 05:16:55 tjl Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + private static Hashtable convert = null; + private Pixels pix = null; + + private static String doConvert(String str) { + if (convert == null) { + convert = new Hashtable(); + String prop = null; + try { + prop = System.getProperty("images.from"); + } catch(Throwable t) {} + if (prop != null) { + StringTokenizer tok = new StringTokenizer(prop, ";="); + while (tok.hasMoreTokens()) { + String a = tok.nextToken(); + String b = tok.nextToken(); + p(""+a+" => "+b); + convert.put(a, b); + } + } + } + for(Enumeration e = convert.keys(); e.hasMoreElements(); ) { + String from = (String)e.nextElement(); + p(""+str+"; "+from); + if (!str.startsWith(from)) continue; + String to = (String)convert.get(from); + p(""+str+" => "+to + str.substring(from.length())); + str = to + str.substring(from.length()); + return str; + } + p("Not converted: "+str); + return str; + } + public Pixels getPixels() + { + if (pix == null) + { + try + { + URL imgURL = new URL(doConvert(getText(""))); + p("URL: "+imgURL); + Image img = Toolkit.getDefaultToolkit().getImage(imgURL); + int w = img.getWidth(null); + int count = 2000000; + while ((w < 0) && (count-- > 0)) w = img.getWidth(null); + int h = img.getHeight(null); + + pix = new Pixels(w, h); + PixelGrabber pg = new PixelGrabber(img, 0, 0, w, h, pix.getPixels(), 0, w); + pg.grabPixels(); + } + catch (Exception e) {} + } + return pix; + } +} + +// Local variables: +// tab-width: 4 +// End: diff --git a/Modules/multimedia/mm.java b/Modules/multimedia/mm.java new file mode 100644 index 0000000..ce754e1 --- /dev/null +++ b/Modules/multimedia/mm.java @@ -0,0 +1,51 @@ +/* +mm.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module; +import org.gzigzag.module.multimedia.*; +import org.gzigzag.*; +import java.awt.*; + +/** + * Module for multimedia stuff. + */ +public class mm +{ + static public final String rcsid = "$Id: mm.java,v 1.3 2001/03/05 08:44:14 deetsay Exp $"; + + static public ZZModule module = new ZZModule() + { + public ZOb newZOb(String id) + { + try + { + return (ZOb)Class.forName("org.gzigzag.module.multimedia." + id).newInstance(); + } + catch (Exception e) + { + // ZZLogger.exc(e); + return null; + } + } + }; +} diff --git a/Modules/multimedia/move.java b/Modules/multimedia/move.java new file mode 100644 index 0000000..826cdeb --- /dev/null +++ b/Modules/multimedia/move.java @@ -0,0 +1,70 @@ +/* +move.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +public class move extends MediaZOb +{ + public static final String rcsid = "$Id: move.java,v 1.2 2001/03/05 08:44:14 deetsay Exp $"; + + Pixels pix = null; + + private int oldframe=0, oldx=0, oldy=0; + + public Pixels getPixels() + { + Pixels inpix = readParam("input").getPixels(); + int x = readParam("x").getInt(0); + int y = readParam("y").getInt(0); + if (pix != null && inpix.getFrame() == oldframe && x == oldx && y == oldy) + { + return pix; + } + oldframe = inpix.getFrame(); oldx = x; oldy = y; + + int w = inpix.getWidth(); + int h = inpix.getHeight(); + + if (pix == null) + { + pix = new Pixels(w, h); + } + else + { + pix.setSize(w, h); + } + + pix.setX(inpix.getX() + x); + pix.setY(inpix.getY() + y); + + int p[] = pix.getPixels(), ip[] = inpix.getPixels(); + for (int i=0; i + +Multimedia module + + + + + +

    1. How to use MediaZObs

    + + + +

    2. How to use macros

    + +To define a macro: +
      +
    • Just use the MediaZOb you want to use ("mm.rect" below).

    • +
    • Replace some of the parameters with the word "param" :-)

    • +
    • To the cell next from "param" on "d.1" write the name of your +parameter. ("mywidth" below)

    • +
    • Optional: To the cell next on "d.1" write a default value.

    • +
    + + + +To use a macro: +
      +
    • Clone the name of the MediaZOb...

    • +
    • Give the clone some of the parameters you have used in your +macro definition.

    • +
    + + diff --git a/Modules/multimedia/rect.java b/Modules/multimedia/rect.java new file mode 100644 index 0000000..6ade2e0 --- /dev/null +++ b/Modules/multimedia/rect.java @@ -0,0 +1,122 @@ +/* +rect.java + * + * Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.*; +import java.awt.*; +import java.awt.image.*; +import java.util.*; + +public class rect extends MediaZOb +{ + public static final String rcsid = "$Id: rect.java,v 1.4 2001/03/05 08:44:14 deetsay Exp $"; + + private Pixels pix = null; + + private int fade(int x, int fg, int bg) + { + int y = 0xff-x; + return 0xff000000 + | (((((fg & 0xff0000) * x) + ((bg & 0xff0000) * y)) >> 8) & 0xff0000) + | (((((fg & 0xff00) * x) + ((bg & 0xff00) * y)) >> 8) & 0xff00) + | (((((fg & 0xff) * x) + ((bg & 0xff) * y)) >> 8) & 0xff); + } + + private int oldw=0, oldh=0, oldbg=0, oldfg=0, oldstarsize=0; + private String oldmode=""; + + public Pixels getPixels() + { + int w = readParam("width").getInt(64); + int h = readParam("height").getInt(64); + int bg = readParam("bg").getInt(0); + int fg = readParam("fg").getInt(0xffffff); + int starsize = readParam("size").getInt(16); + if (starsize==0) starsize=1; + String mode = readParam("fillmode").getText("solid"); + + if (pix != null && oldw==w && oldh==h && oldbg==bg && oldfg==fg + && oldstarsize==starsize && mode.equals(oldmode)) + { + return pix; + } + oldw=w; oldh=h; oldbg=bg; oldfg=fg; oldstarsize=starsize; oldmode=mode; + + if (pix == null) + { + pix = new Pixels(w, h); + } + else + { + pix.setSize(w, h); + } + + int p[] = pix.getPixels(); + if (mode.equals("solid")) + { + for (int i=0; i<(w*h); i++) + { + p[i] = 0xff000000 | fg; + } + } + if (mode.equals("starburst")) + { + // älä optiomoi, vaihda algoritmia + int w2 = w >> 1; + int h2 = h >> 1; + int i = 0, j; + for (int y=-h2; y 0xff) j = 0xff; + p[i++] = fade(j, bg, fg); + } + } + } + if (mode.equals("radial")) + { + int w2 = w >> 1; + int h2 = h >> 1; + int i = 0, j = w, i2 = w*h, j2 = (w*h)-w, k; + for (int y=-h2; y<0; y++) + { + for (int x=-w2; x<0; x++) + { + k = ((int)(Math.atan(((double)x) / y) * 128 / Math.PI)) & 0x3f; + p[i++] = fade(k, bg, fg); + p[--j] = fade(k, fg, bg); + p[--i2] = fade(k | 0x80, bg, fg); + p[j2++] = fade(k | 0x80, fg, bg); + } + i += w2; + j += w + w2; + i2 -= w2; + j2 -= w + w2; + } + } + pix.setFrame(pix.getFrame()+1); + return pix; + } +} diff --git a/Modules/multimedia/sin.java b/Modules/multimedia/sin.java new file mode 100644 index 0000000..2ead486 --- /dev/null +++ b/Modules/multimedia/sin.java @@ -0,0 +1,42 @@ +/* +sin.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tero Mäyränen + */ + +package org.gzigzag.module.multimedia; +import org.gzigzag.module.*; +import org.gzigzag.*; +import java.awt.*; + +/** + */ + +public class sin extends Default +{ + public static final String rcsid = "$Id: sin.java,v 1.1 2001/03/05 08:44:14 deetsay Exp $"; + + public int getInt(int def) + { + int a = ((int)System.currentTimeMillis()) >> 7; + return ((int)(Math.sin(((double)a * readParam("speed").getInt(64)) / (Math.PI * 100)) + * readParam("amplitude").getInt(16))) + readParam("bias").getInt(64); + } +} diff --git a/Modules/nile/Nile1.java b/Modules/nile/Nile1.java new file mode 100644 index 0000000..15f3428 --- /dev/null +++ b/Modules/nile/Nile1.java @@ -0,0 +1,327 @@ +/* +Nile1.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; +import java.io.*; + +/** A stream with parallel markup. + *

    + * Character-level formatting is currently done using B and I (as in HTML, + * for bold and italics). These are placed in cells whose headcell + * on d.nile-fmt-start is the cell in the stream that the + * markup starts from. Likewise, their headcell on d.nile-fmt-end + * is the last cell that does have this markup. + * This is a bit fragile with reordering but most effects can be limited by + * knowing that all formats are allowed to touch only things inside a paragraph + * and we can run a fixer script every once in a while. + *

    + * Paragraph-, section- and chapter -level markup is done by cells + * that say the level: P, H1..H6 on the dimension + * d.nile-struct. These are interpreted by the space part + * so that the HOP operation can be used to move things around easily. + * For higher-than-paragraph level sectioning, the part starting at + * the section, up to the next paragraph or section is considered the + * heading. + * So, in

    H1 foo H2 bar P ab H2 zzz P cd
    , + * the headings would be foo, bar and zzz. + */ + +public class Nile1 { +public static final String rcsid = "$Id: Nile1.java,v 1.10 2001/01/26 13:53:27 ajk Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + ZZUpdateManager.setFast(view); + + ZZCell viewCell = view.getViewcell(); + ZZCell otherCell = viewCell.s("d.nile-wins"); + + boolean split = false; + ZZCell viewAcc = ZZCursorReal.get(viewCell); + ZZCell leftCell = viewAcc.s("d.nile-pair", -1); + ZZCell rightCell = viewAcc.s("d.nile-pair"); + if(leftCell != null || rightCell != null) { + split = true; + + if(leftCell != null) { + rightCell = viewAcc; + viewCell = rightCell; + otherCell = leftCell; + } else { + leftCell = viewAcc; + viewCell = leftCell; + otherCell = rightCell; + } + } + + p("Nile action: id: '"+id+"' key: '"+key+"' code: "+code); + + StringTokenizer st = new StringTokenizer(id); + String[] toks = new String[st.countTokens()]; + for(int i=0; i 1) { + if(toks[1].equals("+")) dir = 1; + else if(toks[1].equals("-")) dir = -1; + + if(toks.length > 2) { + if(toks[2].equals("CHAR")) + unit = new Nile2Unit.Char(); + else if(toks[2].equals("WORD")) + unit = new Nile2Unit.Word(); + else if(toks[2].equals("SENT")) + unit = new Nile2Unit.Sentence(); + else if(toks[2].equals("PARA")) + unit = new Nile2Unit.Paragraph(); + } + } + + id = toks[0]; + + if(id.equals("Cursor")) { + p("Cursor: "+dir); + Nile2Ops.moveCursor(unit, viewCell, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("AdjLeft")) { + Nile2Ops.adjust(unit, viewCell, -1, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("AdjRight")) { + Nile2Ops.adjust(unit, viewCell, 1, dir); + ZZUpdateManager.setFast(null); + } + else if(id.equals("Hop")) { + Nile2Ops.hop(unit, viewCell, dir); + } + else if(id.equals("Mode")) { + Nile2Ops.setCursor(unit, viewCell, null); + if(split) + Nile2Ops.setCursor(unit, otherCell, null); + } + else if(id.equals("Insert")) { + Nile2Ops.insert(viewCell, key); + + // Set the selection of other half to char mode, too + if(split) + Nile2Ops.setCursor(new Nile2Unit.Char(), otherCell, null); + } + else if(id.equals("BackSpace")) { + Nile2Ops.backspace(unit, viewCell); + } + else if(id.equals("Delete")) { + Nile2Ops.del(unit, viewCell); + } + else if(id.equals("BreakParagraph")) { + Nile2Ops.breakParagraph(unit, viewCell); + } + else if(id.equals("Tunnel")) { + if(otherCell != null) { + Nile2Ops.tunnel(unit, otherCell, viewCell, dir, false); + } + } + else if(id.equals("Transcopy")) { + if(otherCell != null) { + Nile2Ops.tunnel(unit, otherCell, viewCell, dir, true); + } + } + else if(id.equals("PUICopy")) { + ZZCell c = ZZCursorReal.get(viewCell); + String s = Nile2Ops.stringify(c); + ZZUtil.puiCopy(s); + } +/* + else if(id.equals("TraverseTranscopies")) { + Nile2Ops.traverseTranscopies(viewCell, dir); + } +*/ + + Object ob = null; + if(pt != null) + ob = xi.getObjectAt(pt.x, pt.y); + + if(id.equals("MouseSetCursor")) { + p("Setting cursor from mouse! Unit: "+unit); + if(split) { + // Brute force: was the click in left window half? + if(pt.x < ((FlobSet)xi).getSize().width/2) { + viewCell = leftCell; otherCell = rightCell; + } else { + viewCell = rightCell; otherCell = leftCell; + } + ZZCursorReal.set(view.getViewcell(), viewCell); + } + Nile2Ops.setCursor(unit, viewCell, (ZZCursor)ob); + } + } + + public ZOb newZOb(String id) { + if(id.equals("Normal")) { + return new Nile1View(); + } else if(id.equals("Parallel")) { + return new SplitNileView(); + } + return null; + } + }; + + + // This is really hacky part... + static ZZCell curAct; + static void a(String key, String act) { a(key, act, null); } + static void a(String key, String act, ZZCell next) { + curAct = curAct.N("d.2", 1); + curAct.setText(key); + ZZCell n = curAct.N("d.1", 1); + n.setText("Nile1." + act); + if(next != null) + next.insert("d.3", 1, n); + } + + static void actions(ZZCell start) { + start.setText("Nile char"); + ZZCell nchar = start; + ZZCell nword = nchar.N("d.1", 1); nword.setText("Nile word"); + ZZCell nsent = nword.N("d.1", 1); nsent.setText("Nile sent"); + ZZCell npara = nsent.N("d.1", 1); npara.setText("Nile para"); + + ZZCell ncommon = npara.N("d.1", 1); ncommon.setText("Nile common"); + + curAct = nword; + // Annoying - these should be structurally + // describable!!! + a("MouseClicked1", "MouseSetCursor 0 WORD"); + a("Backspace", "BackSpace 0 WORD"); + a("Delete", "Delete 0 WORD"); + a("Alt-Backspace", "Delete 0 WORD"); + a("Ctrl-P", "Tunnel - WORD"); // P for pull + a("Ctrl-T", "Transcopy - WORD"); + a("Left", "Cursor - WORD"); + a("Right", "Cursor + WORD"); + a("Shift-Left", "AdjLeft - WORD"); + a("Shift-Right", "AdjRight + WORD"); + a("Ctrl-Left", "AdjRight - WORD"); + a("Ctrl-Right", "AdjLeft + WORD"); + a("Alt-Left", "Hop - WORD"); + a("Alt-Right", "Hop + WORD"); + a("Enter", "BreakParagraph 0 WORD"); + + a("Up", "Cursor - SENT"); + a("Down", "Cursor + SENT"); + a("Alt-Up", "Hop - SENT"); + a("Alt-Down", "Hop + SENT"); + + a("INSERT", "Insert", nchar); + a("Tab", "Mode 0 SENT", nsent); + + curAct = nsent; + a("MouseClicked1", "MouseSetCursor 0 SENT"); + a("Backspace", "BackSpace 0 SENT"); + a("Delete", "Delete 0 SENT"); + a("Alt-Backspace", "Delete 0 SENT"); + a("Ctrl-P", "Tunnel - SENT"); // P for push + a("Ctrl-T", "Transcopy - SENT"); + a("Left", "Cursor - SENT"); + a("Right", "Cursor + SENT"); + a("Shift-Left", "AdjLeft - SENT"); + a("Shift-Right", "AdjRight + SENT"); + a("Ctrl-Left", "AdjRight - SENT"); + a("Ctrl-Right", "AdjLeft + SENT"); + a("Alt-Left", "Hop - SENT"); + a("Alt-Right", "Hop + SENT"); + a("Enter", "BreakParagraph 0 SENT"); + + a("Up", "Cursor - PARA"); + a("Down", "Cursor + PARA"); + a("Alt-Up", "Hop - PARA"); + a("Alt-Down", "Hop + PARA"); + + a("INSERT", "Insert", nchar); + a("Tab", "Mode 0 CHAR", nchar); + +/* + curAct = npara; + a("MouseClicked1", "MouseSetCursor 0 PARA"); + a("Backspace", "BackSpace 0 PARA"); + a("Delete", "Delete 0 PARA"); + a("Alt-Backspace", "Delete 0 PARA"); + a("Left", "Cursor - PARA"); + a("Right", "Cursor + PARA"); + a("Shift-Left", "AdjLeft - PARA"); + a("Shift-Right", "AdjRight + PARA"); + a("Ctrl-Left", "AdjRight - PARA"); + a("Ctrl-Right", "AdjLeft + PARA"); + a("Alt-Left", "Hop - PARA"); + a("Alt-Right", "Hop + PARA"); + + a("INSERT", "Insert"); + a("Tab", "Mode 0 CHAR", nchar); + */ + + curAct = nchar; + a("MouseClicked1", "MouseSetCursor 0 CHAR"); + a("Left", "Cursor - CHAR"); + a("Right", "Cursor + CHAR"); + a("Backspace", "BackSpace 0 CHAR"); + a("Delete", "Delete 0 CHAR"); + a("Alt-Backspace", "Delete 0 CHAR"); + a("INSERT", "Insert"); + a("Tab", "Mode 0 WORD", nword); + a("Enter", "BreakParagraph 0 CHAR"); + + a("Ctrl-C", "PUICopy 0 CHAR"); + + a("Up", "Cursor - WORD"); + a("Down", "Cursor + WORD"); + + } + + static String[][] actions = { + { "MouseClicked1", "Nile1.MouseSetCursor" }, + { "Left", "Nile1.Cursor -" }, + { "Right", "Nile1.Cursor +" }, + { "Shift-Left", "Nile1.AdjLeft -" }, + { "Shift-Right", "Nile1.AdjRight +" }, + { "Ctrl-Left", "Nile1.AdjRight -" }, + { "Ctrl-Right", "Nile1.AdjLeft +" }, + { "Alt-Left", "Nile1.Hop -" }, + { "Alt-Right", "Nile1.Hop +" }, + + { "INSERT", "Nile1.Insert" } + }; + +} + + +// vim: set syntax=java : diff --git a/Modules/nile/Nile1Div.java b/Modules/nile/Nile1Div.java new file mode 100644 index 0000000..f576dd4 --- /dev/null +++ b/Modules/nile/Nile1Div.java @@ -0,0 +1,71 @@ +/* +Nile1Div.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +/** A representation of a particular way of dividing up the nile stream. + * For instance, words, sentences, clauses, paragraphs or user-specified + * split points could be represented this way. + * It is allowed to have an non-zero-width break between the divisions. + *

    + * It is assumed that no elements will be zero-width. + */ + +public interface Nile1Div { +String rcsid = "$Id: Nile1Div.java,v 1.1 2000/11/20 17:36:13 tjl Exp $"; + + /** Find the next break. + * To iterate, over breaks, pass the start2 returned + * from the previous iteration + * as start to the next and set includeThis to false. + *

    + * An important property here is that the stream may be cut + * at any location returned in end2. + * + * @param start The location to start from + * @param dir The direction to move into, 1 or -1. + * @param includeThis Whether to exclude the break where + * @param start2 The cursor to store the start of the next break in. + * @param end2 The cursor to store the end of the next break in. + * @return true if next break found. + */ + boolean findBreak(ZZCursor start, + int dir, boolean includeThis, + ZZCursor start2, ZZCursor end2); + + /** Cut the stream at a boundary specified + * by this division. + * @param start An end of a break. This MUST have been returned by + * findBreak as start2 or end2. + */ + + /** Splice two pieces of the stream, so that between them a division + * of this level is maintained. + */ + ZZCell splice(ZZCell p1, ZZCell p2); +} + + + + diff --git a/Modules/nile/Nile1GenTreeModel.java b/Modules/nile/Nile1GenTreeModel.java new file mode 100644 index 0000000..7497e0a --- /dev/null +++ b/Modules/nile/Nile1GenTreeModel.java @@ -0,0 +1,81 @@ +/* +Nile1GenTreeModel.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +/** The nile1 structural model for GenTreePart. + * This implements the nile1 structural model from H1 to P levels as a + * tree using GenTreePart. + * @see GenTreePart + */ + +public class Nile1GenTreeModel implements GenTreePartModel { +public static final String rcsid = "$Id: Nile1GenTreeModel.java,v 1.3 2000/11/22 00:35:41 tjl Exp $"; + public static boolean dbg = true; + final static void p(String s) { if(dbg) System.out.println(s); } + final static void pa(String s) { System.out.println(s); } + + public int depth() { + return 7; + } + + public int depth(ZZCell c) { + if(c.s("d.nile-struct", -1) == null) return -1; + return Nile1Ops.getLevel(c); + } + + public ZZCell getNext(int mindepth, ZZCell c, int steps) { + if(steps == 0) return c; + c = c.s("d.nile-struct", -1); + int dir = (steps > 0 ? 1 : -1); + ZZCell lasthdr = null; + while(steps != 0 && c != null) { + c = c.s("d.nile", dir); + if(c == null) return null; + lasthdr = c.s("d.nile-struct", 1); + if(lasthdr == null) continue; + if(depth(lasthdr) < mindepth) continue; + steps -= dir; + } + if(c == null) return null; + return lasthdr; + } + + public void disconnectNeg(ZZCell c) { + p("Model: disconnectneg "+c); + c.s("d.nile-struct", -1).disconnect("d.nile", -1); + } + + public void connect(ZZCell c, ZZCell d) { + p("Model: connect "+c+" "+d); + c.s("d.nile-struct", -1).h("d.nile", 1).connect("d.nile", + d.s("d.nile-struct", -1)); + } + + public void setDepth(ZZCell c, int d) { + if(depth(c) < 0) return; + Nile1Ops.setLevel(c, d); + } + +} diff --git a/Modules/nile/Nile1Ops.java b/Modules/nile/Nile1Ops.java new file mode 100644 index 0000000..d804132 --- /dev/null +++ b/Modules/nile/Nile1Ops.java @@ -0,0 +1,479 @@ +/* +Nile1Ops.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +/** A library of routines for operating on Nile1 streams. + * @see Nile1 + * @deprecated Use Nile2Ops. + */ + +public abstract class Nile1Ops { +public static final String rcsid = "$Id: Nile1Ops.java,v 1.16 2000/12/07 00:37:19 tjl Exp $"; + public static boolean dbg = true; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + /** Split the given cell into two at the offset offset. + * The original cell will remain the first. + * Returns the cell that is after the split. + * If offset is zero or greater than or equal to the number of characters + * in c, nothing is done and either the current cell or the next cell is + * returned. + *

    + * The most special case involves doing this at the very end of the stream, + * in which case an empty new cell is created and returned. + * @param c The cursor to split at + * @param always Whether to split even if the offset is at the beginning + * or end of a cell. Used e.g. for inserting a paragraph. + * @return Never null. + */ + static public ZZCell split(ZZCursor c, boolean always) { + // XXX Adjust cursors!!! + ZZCell c0 = c.get(); + int offs = c.getOffs(); + if(always) { + ZZCell c1 = c0.N("d.nile"); + String s = c0.getText(); + c0.setText(s.substring(0, offs)); + c1.setText(s.substring(offs)); + return c1; + } else { + if(offs == 0) return c0; + if(offs == c0.getText().length()) + return c0.getOrNewCell("d.nile"); + return split(c, true); + } + } + + /** Break a paragraph at the given position. + * Returns the first cell of the (possibly empty) new paragraph. + */ + static public ZZCell breakParagraph(ZZCursor c) { + ZZCell n = split(c, true); + if(n.s("d.nile-struct") != null) + throw new ZZError("split structure already!"); + ZZCell str = n.N("d.nile-struct"); + setStrLevel(str, 0); + return n; + } + + /** Change the structural level of a paragraph. + * @param c Any cell in the paragraph - does not need to be the first. + * @param level The new level. + */ + static public void setLevel(ZZCell c, int level) { + ZZCell para = findStruct(c, -1, true); + ZZCell str = para.s("d.nile-struct"); + if(str == null) return; + setStrLevel(str, level); + } + + /** Get the level of a paragraph. + * @param c Any cell in the paragraph - does not need to be the first. + */ + static public int getLevel(ZZCell c) { + ZZCell para = findStruct(c, -1, true); + ZZCell str = para.s("d.nile-struct"); + if(str == null) return 6; + return getStrLevel(str); + } + + /** Insert the given string into the stream at cursor. + */ + static public void insert(ZZCursor c, String txt) { + throw new ZZError("Not implemented"); + } + + + + + /** The level of structure the given structure cell is. + * Note that the levels are a bit interesting: it returns + * zero for paragraphs, 1 for H6, 2 for H5 and so on. + * -1 is returned for cells that are not at a structural border. + */ + static int getStrLevel(ZZCell str) { + String txt = str.getText(); + if(txt.equals("MP")) // Middle of paragraph - special level. + return -1; + if(txt.equals("P")) + return 0; + if(txt.equals("H1")) + return 6; + if(txt.equals("H2")) + return 5; + if(txt.equals("H3")) + return 4; + if(txt.equals("H4")) + return 3; + if(txt.equals("H5")) + return 2; + if(txt.equals("H6")) + return 1; + throw new ZZError("Invalid nile-struct "+txt); + } + + static String[] levels = new String[] { + "P", "H6", "H5", "H4", "H3", "H2", "H1" + }; + + /** Set the level of a structural cell. + */ + static void setStrLevel(ZZCell str, int level) { + if(level < 0 || level > levels.length) + throw new ZZError("Request to set invalid level! "+level); + str.setText(levels[level]); + } + + /** Find an angle in the rank, i.e.the next cell on a rank with + * a connection into a certain direction. + */ + static ZZCell findAngle(ZZCell c, String dim, int dir, + String adim, int adir, boolean includeThis) { + LoopDetector ld = new LoopDetector(); + if(includeThis && c.s(adim, adir) != null) return c; + c = c.s(dim, dir); + while(c != null) { + if(c.s(adim, adir) != null) return c; + ld.detect(c); + c = c.s(dim, dir); + } + return null; + } + + /** Find the next or previous cell that is a structural level element. + */ + static ZZCell findStruct(ZZCell c, int dir, boolean includeThis) { + ZZCell ret = findAngle(c, "d.nile", dir, "d.nile-struct", 1, includeThis); + if(ret == null && dir == -1) { + if(!includeThis && c.s("d.nile", -1) == null) + return null; + return c.h("d.nile", -1); + } + return ret; + } + + /** An editing mode, i.e.the definition of what are the breaks + * that are being operated on in this mode. + */ + public interface Mode { + /** Set the mode cursor, and possibly selection cursor, to the + * given cursor. + * This is called in response to e.g. mouse click, so the position + * may be adjusted to the beginning of the previous unit. + */ + void setCursor(ZZCell view, ZZCursor c); + + /** Move the cursor nsteps units. + */ + void moveCursor(ZZCell view, int nsteps); + + /** Extend/shrink the selection by n units in given direction. + */ + void adjust(ZZCell view, int end, int nsteps); + + /** Hop the selection. + */ + void hop(ZZCell view, int nsteps); + + /** Delete the current selection, move cursor backwards or forwerds. + */ + // void delete(ZZCell view, int movedir); + } + + public static class EdgeMode implements Mode { + Nile1Text.Edger edger; + EdgeMode(Nile1Text.Edger edger) { this.edger = edger; } + + public void setCursor(ZZCell view, ZZCursor c) { + Stream.Iterator iter = giter(c); + edger.edge(iter, true, -1, Nile1Text.START); + curs(view).set(iter.get()); + edger.edge(iter, false, 1, Nile1Text.END); + endcurs(view).set(iter.get()); + } + // Move from end of area if forwards, from start if backwards. + public void moveCursor(ZZCell view, int nsteps) { + if(nsteps <= 0) { + Stream.Iterator iter = giter(curs(view)); + if(!edger.edge(iter, false, nsteps, Nile1Text.START)) + return; + curs(view).set(iter.get()); + edger.edge(iter, false, 1, Nile1Text.END); + endcurs(view).set(iter.get()); + } else { + Stream.Iterator iter = giter(endcurs(view)); + if(!edger.edge(iter, false, nsteps, Nile1Text.END)) + return; + endcurs(view).set(iter.get()); + edger.edge(iter, false, -1, Nile1Text.START); + curs(view).set(iter.get()); + } + } + public void adjust(ZZCell view, int end, int nsteps) { + ZZCursor c1 = curs(view); + ZZCursor c2 = endcurs(view); + if(end < 0) { + Stream.Iterator iter = Stream.getIterator(c1, "d.nile"); + if(!edger.edge(iter, false, nsteps, Nile1Text.START)) + return; + ZZCursor curs = iter.get(); + if(!isOrdered(curs, c2)) return; + c1.set(curs); + } else { + Stream.Iterator iter = Stream.getIterator(c2, "d.nile"); + if(!edger.edge(iter, false, nsteps, Nile1Text.END)) + return; + ZZCursor curs = iter.get(); + if(!isOrdered(c1, curs)) return; + c2.set(curs); + } + // XXX Check that they do not cross... + } + public void hop(ZZCell view, int nsteps) { + p("Cut out the selection for hop"); + ZZCell selec = cutSelection(view); + if(selec == null) return; + + ZZCursor c1 = curs(view); + + p("Now, find place to paste at hopped location"); + Stream.Iterator iter = Stream.getIterator(c1, "d.nile"); + edger.edge(iter, false, nsteps, Nile1Text.START); + c1.set(iter.get()); + p("And paste"); + paste(view, selec, true); + + } + } + static Mode wordmode = new EdgeMode(new Nile1Text.WordEdger()); + static Mode sentencemode = new EdgeMode(new Nile1Text.SentenceEdger()); + + static public Mode getMode(ZZCell view) { + // return wordmode; + return sentencemode; + } + + // XXX + static ZZCell adjStart(ZZCell c, int adj) { + if(adj > 0) { + // XXX Easily screws up font change! + ZZCursor c1 = new ZZCursorVirtual(c, 0); + if(!Stream.move(c1, "d.nile", adj)) + throw new ZZError("ARRRRGH!"); + if(c1.get().equals(c)) { + c.setText(c.getText().substring(adj)); + } else { + c = split(c1, false); + c.disconnect("d.nile", -1); + } + } else if(adj < 0) { + // XXX Spans + String s = ""; + while(adj++ < 0) s = s + " "; // XXX + ZZCell n = c.N("d.nile", -1); + n.setText(s); + } + return c; + } + + static ZZCell adjEnd(ZZCell c, int adj) { + if(adj > 0) { + ZZCursor c1 = new ZZCursorVirtual(c, c.getText().length()); + if(!Stream.move(c1, "d.nile", -adj)) + throw new ZZError("ARRRRGH!"); + // XXX + + c = c1.get(); + c.setText(c.getText().substring(0, c1.getOffs())); + c.disconnect("d.nile", 1); + } else if(adj < 0) { + c.setText(c.getText()+" "); + } + return c; + } + + static void adjustSelection(Stream.Iterator start, Stream.Iterator end) { + Nile1Text.wordEdge(start, true, 1, Nile1Text.START); + Nile1Text.wordEdge(end, true, -1, Nile1Text.END); + } + + static ZZCell cutSelection(ZZCell view) { + ZZCursor curs1 = curs(view); + + p("Cut"); + dump(curs1.get()); + + ZZCursor curs2 = endcurs(view); + if(!isOrdered(curs1, curs2)) return null; + Stream.Iterator iter1 = Stream.getIterator(curs1, "d.nile"); + Stream.Iterator iter2 = Stream.getIterator(curs2, "d.nile"); + int[] adj = new int[2]; + Nile1Text.adjustCut(iter1, iter2, adj); + ZZCursor c1 = iter1.get(); + ZZCursor c2 = iter2.get(); + + ZZCell after = split(c2, false); + p("\nAFTER SPLIT:"); + dump(after); + + ZZCell first = split(c1, false); + p("\nFIRST SPLIT:"); + dump(first); + + + ZZCell prev = first.s("d.nile", -1); + ZZCell last = after.s("d.nile", -1); + after.disconnect("d.nile", -1); + first.disconnect("d.nile", -1); + + if(prev != null) prev.connect("d.nile", after); + + p("AFTER RECONNECT"); + dump(prev); + + curs(view).set(after); + curs(view).setOffs(0); + + // Now, if more characters need to be left out, do it. + first = adjStart(first, adj[0]); + last = adjEnd(last, adj[1]); + if(adj[1] != 0) throw new ZZError("End adj not implemented"); + + p("AFTER CUTADJ"); + dump(first); + + return first; + } + + /** Paste the given stream into the given cursor. + * The range and the text are adjusted for word-by-word + * insertion. + * @param view The viewcell that gives the location to + * paste into. Used later to set the new range, + * if desired. + * @param what The first cell of the stream to paste in. + * @param setRange Whether to set the selection of the given + * view to the pasted range afterwards. + */ + static void paste(ZZCell view, ZZCell what, boolean setRange) { + + ZZCursor v = curs(view); + + p("PASTE"); + dump(v.get()); + p("PASTING WHAT"); + dump(what); + + int[] adj = new int[2]; + Stream.Iterator to = Stream.getIterator(v, "d.nile"); + Stream.Iterator start = giter(new ZZCursorVirtual(what, 0)); + ZZCell last = what.h("d.nile", 1); + Stream.Iterator end = giter(new ZZCursorVirtual(last, + last.getText().length())); + + Nile1Text.adjustPaste(to, start, end, adj); + + what = adjStart(start.get().get(), adj[0]); + adjEnd(end.get().get(), adj[1]); + + p("WHAT ADJUSTED"); + dump(what); + + ZZCell after = split(v, false); + ZZCell before = after.s("d.nile", -1); + after.disconnect("d.nile", -1); + after.connect("d.nile", -1, what.h("d.nile", 1)); + if(before != null) + before.connect("d.nile", 1, what); + + if(setRange) { + v.set(what); + v.setOffs(0); + + start = giter(v); + + ZZCursor ev = endcurs(view); + ev.set(after); + ev.setOffs(0); + + end = giter(ev); + + adjustSelection(start, end); + + v.set(start.get()); + ev.set(end.get()); + } + + p("AFTER EVERYTHING"); + dump(what); + } + + // XXX Should use the tree for help... + static public boolean isOrdered(ZZCursor cu1, ZZCursor cu2) { + ZZCell c1 = cu1.get(); + ZZCell c2 = cu2.get(); + if(c1 == null || c2 == null) return false; + if(c1.equals(c2)) + return cu1.getOffs() <= cu2.getOffs(); + for(; c1 != null && !c1.equals(c2); c1 = c1.s("d.nile")); + if(c1 == null) return false; + return (c1.equals(c2)); + } + + // Shorthand... + static public ZZCursorReal curs(ZZCell view) { + return new ZZCursorReal(view); + } + static public Stream.Iterator giter(ZZCursor c) { + return Stream.getIterator(c, "d.nile"); + } + + static public ZZCursorReal endcurs(ZZCell view) { + ZZCell end = view.getOrNewCell("d.nile-sel"); + return new ZZCursorReal(end); + } + + static public void dump(ZZCell start) { + if(start == null) { + pa("Nile stream Null start!"); + return; + } + ZZCell init = start.h("d.nile", -1); + pa("Nile stream! "+start); + boolean first = true; + for(ZZCell c = init; c != null; c=c.s("d.nile")) { + pa((c.s("d.nile-struct") != null ? "***S*** " : " ") + + " Cell "+c+" "+ + (c.equals(start) ? " <----------------START" : "")); + if(!first && c.equals(init)) { + pa(" WAS A LOOOOOOOP!!!!!!!!!!"); + throw new ZZFatalError("LOOPING NILE STREAM! BAD BAD TROUBLE!"); + } + first = false; + } + } + +} diff --git a/Modules/nile/Nile1Text.java b/Modules/nile/Nile1Text.java new file mode 100644 index 0000000..52b30e3 --- /dev/null +++ b/Modules/nile/Nile1Text.java @@ -0,0 +1,356 @@ +/* +Nile1Text.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +/** A library of routines for operating on streams with Nile1 text model. + * @see Nile1 + * @deprecated Use Nile2Unit + */ + +public abstract class Nile1Text { +public static final String rcsid = "$Id: Nile1Text.java,v 1.9 2000/12/07 00:37:19 tjl Exp $"; + public static boolean dbg = true; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + // Stream.Iterator iter = Stream.getIterator(start, "d.nile"); + + static public int START = 1; + static public int END = -1; + static public int ANY = 0; + + static boolean isWordBreak(Stream.Iterator iter, int edge) { + char cur = iter.getChar(); + if(cur == -1) return true; + if(!iter.move(-1)) return true; + char prev = iter.getChar(); + iter.move(1); + return isWordBreak(prev, cur, edge); + } + + static boolean isWordBreak(char prev, char cur, int edge) { + boolean ret = isWordBreak0(prev, cur, edge); + p("IsWordBreak: '"+prev+"' '"+cur+"' "+edge+ " RETURNING: "+ret); + return ret; + } + static boolean isWordBreak0(char prev, char cur, int edge) { + boolean curlet = Character.isLetterOrDigit(cur); + boolean curws = Character.isWhitespace(cur); + boolean prevlet = Character.isLetterOrDigit(prev); + boolean prevws = Character.isWhitespace(prev); + + if(!curlet && !curws) { + if(edge != END) return true; // punctuation -> break start + return prevlet || !prevws; // punct -> br end if prev ltr or punct + } + if(prevlet && curlet) return false; + if(prevlet && curws) return edge != START; + // --> prevlet == false + if(!prevws) { // previous was punctuation -> + if(edge != START) return true; + return curlet; // Starting edge only if this is a letter. + } + if(prevws && curws) return false; + if(prevws && curlet) return edge != END; + // shouldn't get here + throw new ZZError("isWordBreak logic error!"); + } + + /** Find the nsteps:th next wordbreak. + * Always alters iter. + *

    + * Characters are split into three categories: + * letter-or-digit, whitespace and other. + * whitespace is always a word boundary (but there is no + * word boundary between two whitespace characters). + * The characters in the other category are words by themselves. + * So basically there is a word break at character c, if + *

      + *
    • c is the first character in the stream. + *
    • c is one beyond the last character in the stream + *
    • c is punctuation + *
    • c is of a different category (see above) than + * the character just before it. + *
    + * @param nsteps The number of steps, a positive or negative number. + * @param edge Which edge of the word do we want: START, END or ANY. + */ + static public boolean wordEdge(Stream.Iterator iter, + boolean includeThis, int nsteps, + int edge) { + if(nsteps == 0) throw new ZZError("Can't step 0 words"); + int dir = (nsteps > 0 ? 1 : -1); + for(; nsteps != 0; nsteps -= dir) { + if(!wordEdge0(iter, includeThis, dir, edge)) + return false; + includeThis = false; + } + return true; + } + + static private boolean wordEdge0(Stream.Iterator iter, + boolean includeThis, int dir, + int edge) { + char prev = 0; + char cur = iter.getChar(); + + if(dir > 0) { + if(includeThis) { + if(!iter.move(-dir)) return true; + prev = iter.getChar(); + iter.move(dir); + if(isWordBreak(prev, cur, edge)) return true; + } + while(iter.move(dir)) { + prev = cur; + cur = iter.getChar(); + if(cur == -1) return true; // Ran into end of text. + if(isWordBreak(prev, cur, edge)) return true; + } + return (edge != START); + } else { + if(!includeThis) { + if(!iter.move(dir)) return false; + cur = iter.getChar(); + } + while(iter.move(dir)) { + prev = cur; + cur = iter.getChar(); + if(isWordBreak(cur, prev, edge)) { + iter.move(-dir); + return true; + } + } + return (edge != END); + } + } + + static public boolean sentenceEdge(Stream.Iterator iter, + boolean includeThis, int nsteps, int edge) { + if(nsteps == 0) throw new ZZError("Can't step 0 words"); + int dir = (nsteps > 0 ? 1 : -1); + for(; nsteps != 0; nsteps -= dir) { + if(!sentenceEdge0(iter, includeThis, dir, edge)) + return false; + includeThis = false; + } + return true; + } + + static public boolean sentenceEdge0(Stream.Iterator iter, + boolean includeThis, int dir, int edge) { + if(edge == 0) + throw new ZZError("Looking for either sentence edge not implemented"); + if(edge == START) { + // If we cannot move, we're at the beginning. + if(!iter.move(-1)) + if(dir < 0 || includeThis) return includeThis; + // Back out + iter.move(1); + // Back up two, one by one, and then search non-inclusive. + iter.move(-1); + iter.move(-1); + if(iter.find(dir, includeThis, " ")) { + iter.move(2); + return true; + } else { + // There is a start in the beginning, but not at the end. + iter.end(dir); + return (dir < 0); + } + } else { + if(!iter.move(1)) return includeThis; + iter.move(-1); + // Here we just find because end is at the found text + if(iter.find(dir, includeThis, " ")) + return true; + else { + iter.end(dir); + // There is an end in the end, but not at the beginning. + return (dir > 0); + } + } + } + + static boolean ws(char c) { return Character.isWhitespace(c); } + static boolean punct(char c) { + return (!Character.isWhitespace(c)) && (!Character.isLetterOrDigit(c)); + } + static boolean lett(char c) { return Character.isLetterOrDigit(c); } + + /** Adjust the locations to cut text from. + * Basically, cut one or two spaces after the latter location, + * and if none, and there is a single space preceding, + * cut it along. + *

    + * @param leaveout An output parameter: the values in the two-member + * array are set to the number of characters + * to leave out of the cut text. + * An important meaning is given to negative + * values: a negative value means "add this many + * spaces". + */ + static public void adjustCut(Stream.Iterator iter1, + Stream.Iterator iter2, + int[] leaveout) { + leaveout[0] = leaveout[1] = 0; + // First off, do not adjust if one of them is not word end. + if(!isWordBreak(iter1, START) || !(isWordBreak(iter2, END))) return; + + char c1 = iter2.getChar(0); + char c2 = iter2.getChar(1); + + // If there are one or two spaces afterwards, cut them along. + if(ws(c1)) { + iter2.move(1); + if(ws(c2)) + iter2.move(1); + } else { + // If there is one character before... + char b1 = iter1.getChar(-1); + char b2 = iter1.getChar(-2); + if(ws(b1) && !ws(b2)) { + // This is a tricky situation. What we have here is + // cutting off in + // word WORD, word + // without the comma. + // The space before WORD needs to be removed. + // This is what the leaveout means. + // + // Additionally, for pasting at the correct boundary + // to work right, we need to add a space *after* this + // word when pasting. See adjustPaste. + iter1.move(-1); + leaveout[0] = 1; + } + } + } + + /** The adjustment to a paste operation. + * @param adjust Analogour to the leaveout parameter of + * adjustCut. Positive values mean + * leaving this many characters out + * and negative values mean + * adding that many spaces. + */ + static public void adjustPaste(Stream.Iterator to, + Stream.Iterator start, + Stream.Iterator end, + int[] adjust) { + adjust[0] = adjust[1] = 0; + if(!isWordBreak(to, START)) return; + + // If to is at a letter-punct edge, make sure + // pasted text starts with space and does not end with one. + // Otherwise, make sure it ends with space but doesn't start + // with it. + + char c1 = to.getChar(-1); + char c2 = to.getChar(0); + if(lett(c1) && punct(c2)) { + // Now, start but don't end with space. + if(!ws(start.getChar(0))) adjust[0] = -1; + if(ws(end.getChar(-1))) adjust[1] = 1; + } else { + if(ws(start.getChar(0))) adjust[0] = 1; + if(!ws(end.getChar(-1))) adjust[1] = -1; + } + } + + static public boolean paragraphEdge(Stream.Iterator iter, + boolean includeThis, int nsteps, int edge) { + if(nsteps == 0) throw new ZZError("Can't step 0 paragraphs"); + int dir = (nsteps > 0 ? 1 : -1); + for(; nsteps != 0; nsteps -= dir) { + if(!paragraphEdge0(iter, includeThis, dir, edge)) + return false; + includeThis = false; + } + return true; + } + + static public boolean paragraphEdge0(Stream.Iterator iter, + boolean includeThis, int dir, int edge) { + ZZCell c = iter.get().get(); + int offs = iter.get().getOffs(); + boolean beg = (offs == 0); + boolean end = (offs == c.getText().length()); + if(edge == 0) + throw new ZZError("Can't look for paragraph end / begin"); + // XXX Should we set the end edge to point to negative + // direction? + // if(edge == START) { + if(dir > 0) { + if(!beg || !includeThis) c = c.s("d.nile"); + } else { + if(beg && !includeThis) c = c.s("d.nile", -1); + } + // Now we can go on, using includeThis always. + if(c == null) return false; + c = Nile1Ops.findStruct(c, dir, true); + if(c != null) { + iter.set(new ZZCursorVirtual(c, 0)); + if(edge == START) + iter.move(0, 1); + else + iter.move(0, -1); + return true; + } else { + if(edge == END && dir > 0) { + iter.end(); return true; + } + return false; + } + // } + } + + + public interface Edger { + boolean edge(Stream.Iterator iter, boolean includeThis, int nsteps, + int whichEdge); + } + + static public class WordEdger implements Edger { + public boolean edge(Stream.Iterator iter, boolean includeThis, + int nsteps, int whichEdge) { + return wordEdge(iter, includeThis, nsteps, whichEdge); + } + } + + static public class SentenceEdger implements Edger { + public boolean edge(Stream.Iterator iter, boolean includeThis, + int nsteps, int whichEdge) { + return sentenceEdge(iter, includeThis, nsteps, whichEdge); + } + } + + static public class ParagraphEdger implements Edger { + public boolean edge(Stream.Iterator iter, boolean includeThis, + int nsteps, int whichEdge) { + return paragraphEdge(iter, includeThis, nsteps, whichEdge); + } + } + +} diff --git a/Modules/nile/Nile1View.zob b/Modules/nile/Nile1View.zob new file mode 100644 index 0000000..a1ece1b --- /dev/null +++ b/Modules/nile/Nile1View.zob @@ -0,0 +1,311 @@ +/* +Nile1View.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; +import java.io.*; + +/** A view for nile streams. + */ + +public class Nile1View implements FlobView, ZOb { +public static final String rcsid = "$Id: Nile1View.zob,v 1.4 2001/01/26 13:53:27 ajk Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + + STRUCTPARAMS { + /** The default font to use. + */ + Font font + = new Font("SansSerif", Font.PLAIN, 11); + + /** The distance between paragraphs. + */ + int paraskip + = 8; + + /** The left-side margin for normal text. + * Headings hang left of this margin. + */ + int lmargin + = 50; + + ZOb ftextlayouter + = new FTextLayouter(); + + /** Whether to use a special color for span (transcluded) cells. */ + boolean showcopy + = false; + } + + /** Bold and italic derivatives of the font given. + * The first index is the level of the text i.e. + * from paragraph to H1. + */ + Font[][][] bifonts; + FontMetrics[][][] bifontms; + + INITIALIZE { + bifonts = new Font[7][2][2]; + bifontms = new FontMetrics[7][2][2]; + for(int l = 0; l < bifonts.length; l++) { + int size = font.getSize(); + if(l > 0 && l < 5) size += l-1; + if(l == 5) size += 6; + if(l == 6) size += 9; + bifonts[l][1][0] = new Font(font.getName(), + Font.BOLD, size); + bifonts[l][1][1] = new Font(font.getName(), + Font.BOLD | Font.ITALIC, size); + + if(l == 0) { + bifonts[l][0][0] = new Font(font.getName(), 0, size); + bifonts[l][0][1] = new Font(font.getName(), + Font.ITALIC, size); + } else { // All bold for headers + bifonts[l][0][0] = bifonts[l][1][0]; + bifonts[l][0][1] = bifonts[l][1][1]; + } + for(int b = 0; b<2; b++) + for(int i = 0; i<2; i++) + bifontms[l][b][i] = FONTMETRICS(bifonts[l][b][i]); + } + } + + Color selcolor = Color.white; + Color copycolor = Color.yellow.darker().darker().darker().darker(); + + /** Return the formatted text object for one paragraph. + */ + FText paragraph(ZZCell start, ZZCell endBefore, ZZCursor offsetOfC, + int[]into, + ZZCursor selectEnd) + { + p("Paragraph! "+start+" "+endBefore+" "); + ZZCell selsc = null; + int selso = 0; + if(offsetOfC != null) { + selsc = offsetOfC.get(); + selso = offsetOfC.getOffs(); + } + ZZCell offsetOf = selsc; + ZZCell selec = null; + int seleo = 0; + if(selectEnd != null) { + selec = selectEnd.get(); + seleo = selectEnd.getOffs(); + } + boolean selected = (selsc == null && selec != null); + + if(selso == ZZCursor.NO_OFFSET || selec == null) { + selsc = null; + selec = null; + selected = false; + } + + FText.Part part = null; + + int level = Nile2Iter.getLevel(start); + int curOffs = 0; + int b = 0, i = 0; + Vector parts = new Vector(); + LoopDetector ld = new LoopDetector(); + LoopDetector ld2 = new LoopDetector(); + for(ZZCell c = start; c != null && c != endBefore; c = c.s("d.nile")) { + ld.detect(c); + for(ZZCell fs = c.s("d.nile-fmt-start"); fs != null; + fs = fs.s("d.nile-fmt-start")) { + ld.detect(fs); + if(fs.getText().equals("B")) b++; + else if(fs.getText().equals("I")) i++; + else p("Invalid format: "+fs.getText()); + } + int b0 = (b > 0 ? 1 : 0); + int i0 = (i > 0 ? 1 : 0); + int len = c.getText().length(); + + if(c == offsetOf && into != null) into[0] = curOffs; + int internoffs = 0; + if(c == selsc) { + if(selso > len) { + ZZLogger.log("Warning: start over length "+selso+" "+len); + selso = len; + } + part = new FText.CellPart( c, 0, selso, + bifonts[level][b0][i0], bifontms[level][b0][i0], + null, c.getSpan() == null ? null : copycolor); + parts.addElement(part); + internoffs = selso; + selected = true; + p("Start selection: "+selso+" "+selsc); + } + if(c == selec && seleo >= internoffs) { + if(seleo > len) { + ZZLogger.log("Warning: end over length "+seleo+" "+len); + seleo = len; + } + part = new FText.CellPart( c, internoffs, seleo-internoffs, + bifonts[level][b0][i0], bifontms[level][b0][i0], + selcolor, c.getSpan() == null ? null : copycolor); + parts.addElement(part); + internoffs = seleo; + selected = false; + selectEnd.set((ZZCell)null); + p("End selection: "+seleo+" "+selec); + } + + part = new FText.CellPart( c, internoffs, len-internoffs, + bifonts[level][b0][i0], bifontms[level][b0][i0], + selected ? selcolor : null, + c.getSpan() == null ? null : copycolor); + + parts.addElement(part); + curOffs += len; + + for(ZZCell fe = c.s("d.nile-fmt-end"); fe != null; + fe = fe.s("d.nile-fmt-start")) { + ld2.detect(fe); // Can't use same: same cell is start&end + if(fe.getText().equals("B")) b--; + else if(fe.getText().equals("I")) i--; + else p("Invalid format: "+fe.getText()); + } + } + return new FText(parts); + } + + Rectangle pmarg(Rectangle r, ZZCell para) { + int level = Nile2Iter.getLevel(para); + Rectangle ret = new Rectangle(r); + int w = (6 - level) * lmargin / 6; + ret.x += w; ret.width -= w; + return ret; + } + + boolean[] beginningSentence = new boolean[2]; + public Rectangle placeParagraph(FlobSet into, + FText ft, ZZCell para,Rectangle origrect, + int direction, int initY, int middleOffs) { + beginningSentence[0] = true; + beginningSentence[1] = false; + // Margins. + Rectangle rect = pmarg(origrect, para); + Rectangle ret = ((FTextLayouter)ftextlayouter).place(into, ft, rect, + 1, + direction, initY, middleOffs, false, + beginningSentence); + // Now, do the cool thing with the section headings: include + // previous and next section headings of the same level here. + if(Nile2Iter.getLevel(para) > 0) { + + ZZCell strcell = para.s("d.nile-struct"); + if(strcell == null) return ret; + + for(int dir = -1; dir <= 1; dir += 2) { + ZZCell prevsec = strcell.s("nile1str:breadth",dir); + if(prevsec == null) continue; + prevsec = prevsec.h("nile1str:depth").s("d.nile-struct", -1); + if(prevsec == null) continue; + beginningSentence[0] = true; + beginningSentence[1] = false; + FText nft = paragraph(prevsec, Nile2Iter.findStruct(prevsec, 1, false), + null, null, null); + ((FTextLayouter)ftextlayouter).place(into, nft, rect, 200, + dir, ret.y + (dir < 0 ? 0 : ret.height), + 0, false, beginningSentence); + } + } + return ret; + } + + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + int[] offs = new int[1]; + + LoopDetector ld = new LoopDetector(); + + ZZCursor selectEnd = null; + ZZCell sele = view.s("d.nile-sel"); + if(sele != null) { + selectEnd = ZZCursorVirtual.createFromReal(sele); + } + + // Do the center paragraph first. + ZZCell firstpara = Nile2Iter.findStruct(accursed, -1, true); + ZZCell nextpara = Nile2Iter.findStruct(accursed, 1, false); + + FText ft = paragraph(firstpara, nextpara, new ZZCursorReal(view), + offs, selectEnd); + + Dimension size = into.getSize(); + Rectangle rect = new Rectangle(0, 0, size.width, size.height); + + Rectangle ctr = placeParagraph(into, ft, firstpara, rect, + 0, rect.y+rect.height/2, + ZZCursorReal.getVisualTextOffset(view)); + + // Go into positive direction. + Rectangle r = ctr; + while(nextpara != null) { + ld.detect(nextpara); + ZZCell next = Nile2Iter.findStruct(nextpara, 1, false); + ft = paragraph(nextpara, next, null, null, selectEnd); + + r = placeParagraph(into, ft, nextpara, rect, + 1, r.y+r.height + paraskip, 0); + + nextpara = next; + + if(r.y + r.height > size.height) break; + } + + // And negative. + r = ctr; + while(true) { + ZZCell prev = firstpara; + firstpara = Nile2Iter.findStruct(firstpara, -1, false); + if(firstpara == null) break; + ld.detect(firstpara); + + ft = paragraph(firstpara, prev, null, null, null); + + beginningSentence[0] = true; + r = placeParagraph(into, ft, firstpara, rect, + -1, r.y - paraskip, 0); + + if(r.y < 0) break; + } + // into.dump(); + Flob cursf = into.findFlob(null, accursed); + // p("Cursf: "+cursf); + if(cursf != null) + ((SplitCellFlob1)cursf).addCurs(into, ZZCursorReal.getOffs(view), + Color.red); + } +} + + +// vim: set syntax=java : diff --git a/Modules/nile/Nile2Iter.java b/Modules/nile/Nile2Iter.java new file mode 100644 index 0000000..3dcc7c3 --- /dev/null +++ b/Modules/nile/Nile2Iter.java @@ -0,0 +1,589 @@ +/* +Nile2Iter.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag.module; +import org.gzigzag.*; + +/** A character-level iterator object that knows about + * paragraphs for a Nile stream. + * This object explicitly assumes no modifications to the + * stream while it is working. + */ + +public final class Nile2Iter implements Cloneable { +public static final String rcsid = "$Id: Nile2Iter.java,v 1.8 2000/12/20 22:26:35 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + private ZZCell c; + private int offs; + + // Cache these for speed. + private String ctext; + private int clen; + + private void load(ZZCell c) { + this.c = c; + ctext = c.getText(); + clen = ctext.length(); + } + + private void load(ZZCell c, int offs) { + load(c); + if(offs == -1) this.offs = clen; + else this.offs = offs; + move(0); + } + + private void reload() { + load(c); + move(0); + } + + static private boolean isStruct(ZZCell c) { + if(c == null) + throw new ZZError("Null isStruct?"); + return c.s("d.nile-struct") != null; + } + + Nile2Iter() { } + public Nile2Iter(ZZCursor curs) { set(curs); } + + public void set(ZZCursor curs) { + load(curs.get()); + this.offs = curs.getOffs(); + // Ensure positive bias. + move(0); + } + + public void set(Nile2Iter iter) { + load(iter.c); + offs = iter.offs; + } + + /** Move n characters forwards or backwards within the current + * paragraph. + * If the offset given is out of bounds, moves as far as possible + * and returns false, otherwise returns true. + */ + public boolean move(int n) { + n += offs; + offs = 0; + + // Internally, we like to maintain positive bias always. + // Thus, the greater-OR-EQUALS sign. + while(n >= clen) { + n -= clen; + ZZCell nc = c.s("d.nile"); + if(nc == null || isStruct(nc)) { + // Only situation for negative bias: end of paragraph. + offs = clen; + if(n > 0) return false; + return true; + } + load(nc); + } + while(n < 0) { + ZZCell nc = c.s("d.nile", -1); + if(nc == null || isStruct(nc)) { + offs = 0; + return false; + } + load(nc); + n += clen; + } + + offs = n; + return true; + } + + /** Get the character at current offset. + * Returns -1 if out of bounds. + */ + public int cur() { + if(offs >= clen || offs < 0) return -1; + return ctext.charAt(offs); + } + public int get() { return cur(); } + + public int next() { + if(!move(1)) return -1; + return cur(); + } + + public int prev() { + if(!move(-1)) return -1; + return cur(); + } + + public int get(int at) { + ZZCell cache = c; + int offscache = offs; + int ret = -1; + if(move(at)) { + ret = cur(); + } + if(c != cache) + load(cache); + offs = offscache; + return ret; + } + + /** Move n paragraphs, moving as little as possible. + * This means that if we move backwards, we will be at the end + * of the paragraph and vice versa. + */ + public boolean shiftPara(int n) { + // XXX What about empty paragraphs? A LOT of trouble... + if(n == 0) return true; + int dir = (n > 0 ? 1 : -1); + ZZCell nc = c; + while(n != 0) { + nc = nc.s("d.nile", dir); + if(nc == null) return false; + if(isStruct(nc)) n -= dir; + } + // Now we are at the paragraph cell. + // Need to take one step. + nc = nc.s("d.nile", dir); + if(nc == null) { + return false; // XXX Should set position! + // throw new ZZError("AUGH! Para shifting null next"); + } + load(nc); + offs = (dir < 0 ? clen : 0); + return true; + } + + /** Shift to paragraph beginning or end. + */ + public boolean paraEnd(int dir) { + ZZCell nc = c; + ZZCell prev = nc; + while(nc != null && !isStruct(nc)) { + prev = nc; + nc = nc.s("d.nile", dir); + } + if(nc == null) { + nc = prev; + } else { + nc = nc.s("d.nile", -dir); + } + load(nc); + offs = (dir < 0 ? 0 : clen); + return true; + } + + public void streamEnd(int dir) { + // XXX When going to beginning, may set pos to struct! + ZZCell h = c.h("d.nile", dir); + paraEnd(dir); + } + + /** Get the current position with given bias. + * @param bias Whether we are looking into positive or negative + * direction. If the cursor is at an edge, + * this affects which cell is returned. + */ + public ZZCursor getCursor(int bias) { + // XXX Check para? + if(bias < 0 && offs == 0) { + ZZCell nc = c.s("d.nile", -1); + return new ZZCursorVirtual(nc, nc.getText().length()); + } + return new ZZCursorVirtual(c, offs); + } + public ZZCursor getCursor() { return getCursor(1); } + + + /** Cut the stream at this location. + * This pointer remains pointing to the prior space, + * and it returns a iter at the beginning of the new stream. + */ + public Nile2Iter cut() { + move(0); + Nile2Iter ni = new Nile2Iter(); + if(offs == 0) { + ZZCell prev = c.getOrNewCell("d.nile", -1); + prev.disconnect("d.nile", 1); + ni.load(c, 0); + load(prev); + offs = clen; + return ni; + } + if(offs == clen) { // must be very end. + ZZCell next = c.getOrNewCell("d.nile", 1); + ni.load(next, 0); + c.disconnect("d.nile", 1); + return ni; + } + ZZCell spl = split(c, offs, true); + c.disconnect("d.nile", 1); + reload(); + ni.load(spl, 0); + return ni; + } + + // XXX Cursors easily cut out! + + public void join(Nile2Iter to) { + c.h("d.nile", 1).connect("d.nile", to.c.h("d.nile", -1)); + reload(); + } + + public void adjustSpaceStart(int nstart) { + if(dbg) dumpStream(); + Nile2Iter ctr = (Nile2Iter)clone(); + int ncur = 0; + while(Nile2Unit.ws(ctr.get())) { + ncur ++; ctr.move(1); + } + if(nstart < ncur) { + move(ncur-nstart); + // XXX Cursors could go wild. + set(cut()); + } else if(nstart > ncur) { + StringBuffer buf = new StringBuffer(); + while(nstart-- > ncur) buf.append(' '); + ZZCell n = c.N("d.nile", -1); + n.setText(buf.toString()); + load(n, 0); + } + } + + public void adjustSpaceEnd(int nend) { + + Nile2Iter ctr = (Nile2Iter)clone(); + ctr.streamEnd(1); + int ncur = 0; + while(Nile2Unit.ws(ctr.get(-1))) { + ncur ++; ctr.move(-1); + } + if(nend < ncur) { + ctr.move(nend); // Move back forwards. + // XXX Cursors could go wild. + ctr.cut(); + } else if(nend > ncur) { + StringBuffer buf = new StringBuffer(); + while(nend-- > ncur) buf.append(' '); + ZZCell n = ctr.c.h("d.nile", 1).N("d.nile", 1); + n.setText(buf.toString()); + } + if(dbg) dumpStream(); + } + + public void adjustSpaces(int nstart, int nend) { + p("Adjustspaces: "+nstart+" "+nend); + adjustSpaceStart(nstart); + adjustSpaceEnd(nend); + + } + + public Object clone() { + try { + return super.clone(); + } catch(CloneNotSupportedException e) { + ZZLogger.exc(e); + return null; + } + } + + public void dumpStream() { + pa("Dumping Nile2Iter stream: at offs: "+offs); + dump(c); + } + + /** Returns true if this <= it. + * Throws an error if not in same stream. + */ + public boolean isOrdered(Nile2Iter it) { + if(c.equals(it.c)) { + return offs <= it.offs; + } else { + if(c.findCell("d.nile", 1, it.c)) return true; + if(!c.findCell("d.nile", -1, it.c)) + throw new ZZError("IsOrdered: not on same stream!"); + return false; + } + } + + public void insertInCell(String s) { + ZZCell spl = split(c, offs, true); + spl = spl.N("d.nile", -1); + spl.setText(s); + load(spl, -1); + } + + public void insert(String str) { + ZZCell n = c; + if(isStruct(c)) { + load(c.s("d.nile"), -1); + ZZCell d = n.N("d.nile"); + d.setText(str); + ZZLogger.log("AUGH! Insert at struct cell!"); + // throw new ZZError("Inserting"); + } else if((offs == 0 || offs == clen) && c.getSpan() == null) { + if(offs == clen) { + c.setText(c.getText() + str); + load(c, -1); + } else { // In this case, this iter doesn't move ;) + ZZCell prev = c.s("d.nile", -1); + if(isStruct(prev) || prev == null) + c.N("d.nile", -1).setText(str); + else + prev.setText(prev.getText() + str); + } + } else { + if(offs > 0 && offs < clen) split(c, offs, false); + ZZCell d = c.N("d.nile", offs > 0 ? 1 : -1); + d.setText(str); + load(d, -1); + } + } + + /** Make a cell's content into a span. */ + static public Span spanify(ZZCell c0) { + Span sp = c0.getSpan(); + if(sp != null) return sp; + + StringScroll sc = c0.getSpace().getStringScroll(); + String s = c0.getText(); + long soffs = sc.append(s); + sp = Span.create( + Address.scrollOffs(sc, soffs), + Address.scrollOffs(sc, soffs + s.length() - 1) + ); + c0.setSpan(sp); + return sp; + } + + /** Split the given cell into two at the offset offset. + * The original cell will remain the first. + * Returns the cell that is after the split. + * If offset is zero or greater than or equal to the number of characters + * in c, nothing is done and either the current cell or the next cell is + * returned. + *

    + * The most special case involves doing this at the very end of the stream, + * in which case an empty new cell is created and returned. + * @param c The cursor to split at + * @param always Whether to split even if the offset is at the beginning + * or end of a cell. Used e.g. for inserting a paragraph. + * @return Never null. + */ + static public ZZCell split(ZZCell c0, int offs, boolean always) { + // XXX Adjust cursors!!! + if(always) { + ZZCell c1 = c0.N("d.nile"); + if(c0.s("d.nile-transcluded") != null) { + c0.insert("d.nile-transcluded", 1, c1); + c0.insert("d.nile-transcluded-split", 1, c1); + } + Span sp = c0.getSpan(); + if(sp == null) { + String s = c0.getText(); + c0.setText(s.substring(0, offs)); + c1.setText(s.substring(offs)); + } else { + c0.setSpan(sp.subSpan(0, offs)); + c1.setSpan(sp.subSpan(offs)); + } + return c1; + } else { + if(offs == 0) return c0; + if(offs == c0.getText().length()) + return c0.getOrNewCell("d.nile"); + return split(c0, offs, true); + } + } + + /** Internal convenience: make a connection and a ring if it isn't yet + * This is part of a cheat to make jumping between transclusions work: + * we connect all transclusions of a cell on d.nile-transcluded, even + * if the transcluded spans do not overlap, and jump between them. + * Works because currently, a cell can contain only one span. + * XXX what to do when splitting ??? + * XXX if we cheat anyway, is it more appropriate to use zz clones? + */ + static private void transcluded(ZZCell from, ZZCell to) { + from.insert("d.nile-transcluded", 1, to); + if(from.s("d.nile-transcluded", -1) == null) + from.connect("d.nile-transcluded", -1, to); + } + + + /** Transcopy the part of the stream between two iters. + * Sets the iters to point to the beginning and the end of the transcopied + * stream. + */ + static public void copy(Nile2Iter start, Nile2Iter to) { + if(!start.isOrdered(to)) { + Nile2Iter tmp = to; + to = start; start = tmp; + } + + // First, spanify all cells. + ZZCell d = start.c; + while(true) { + if(!isStruct(d)) spanify(d); + p("Spanified "+d+" is span "+d.getSpan()); + if(d == to.c) break; + d = d.s("d.nile"); + } + + // Next, create the new stream. + ZZCell first, last; + if(start.c.equals(to.c)) { + first = start.c.N(); + last = first; + first.setSpan(start.c.getSpan().subSpan(start.offs, to.offs)); + transcluded(start.c, first); + } else { + first = start.c.N(); + first.setSpan(start.c.getSpan().subSpan(start.offs)); + transcluded(start.c, first); + + ZZCell prev = first; + ZZCell here = start.c.s("d.nile"); + while(here != to.c) { + prev = prev.N("d.nile"); + prev.setSpan(here.getSpan()); + transcluded(prev, here); + here = here.s("d.nile"); + } + + last = prev.N("d.nile"); + last.setSpan(to.c.getSpan().subSpan(0, to.offs)); + transcluded(to.c, last); + } + + // Finally, set the iters. + start.set(new ZZCursorVirtual(first, 0)); + to.set(new ZZCursorVirtual(last, last.getText().length() - 1)); + } + + static public void dump(ZZCell start) { + if(start == null) { + pa("Nile stream Null start!"); + return; + } + ZZCell init = start.h("d.nile", -1); + pa("Nile stream! "+start); + boolean first = true; + for(ZZCell c = init; c != null; c=c.s("d.nile")) { + pa((c.s("d.nile-struct") != null ? "***S*** " : " ") + + " Cell "+c+" "+ + (c.equals(start) ? " <----------------START" : "")); + if(!first && c.equals(init)) { + pa(" WAS A LOOOOOOOP!!!!!!!!!!"); + throw new ZZFatalError("LOOPING NILE STREAM! BAD BAD TROUBLE!"); + } + first = false; + } + } + + static String[] levels = new String[] { + "P", "H3", "H2", "H1" + }; + + static int getMaxLevel() { return levels.length - 1; } + + // XXX Should use clones. + /** Set the level of a structural cell. + */ + static void setStrLevel(ZZCell str, int level) { + if(level < 0 || level > levels.length) + throw new ZZError("Request to set invalid level! "+level); + str.setText(levels[level]); + } + + /** The level of structure the given structure cell is. + * Note that the levels are a bit interesting: it returns + * zero for paragraphs, 1 for H6, 2 for H5 and so on. + * -1 is returned for cells that are not at a structural border. + */ + static int getStrLevel(ZZCell str) { + String txt = str.getText(); + for(int i=0; i 0) { + iter = giter(endcurs(view)); + if(!unit.insertPos(iter, 1, true)) return; + } else { + iter = giter(curs(view)); + if(!unit.insertPos(iter, -1, false)) return; + } + curs(view).set(iter.getCursor()); + unit.end(iter, 1, false); + endcurs(view).set(iter.getCursor()); + } + + static public void adjust(Nile2Unit unit, ZZCell view, int end, int dir) { + clearSavedCursor(view); + Nile2Iter iter = giter(curs(view)); + Nile2Iter enditer = giter(endcurs(view)); + if(end > 0) { + if(!unit.end(enditer, dir, false)) return; + } else { + if(!unit.start(iter, dir, false)) return; + } + if(!iter.isOrdered(enditer)) + return; + curs(view).set(iter.getCursor()); + endcurs(view).set(enditer.getCursor()); + } + + static public void hop(Nile2Unit unit, ZZCell view, int dir) { + clearSavedCursor(view); + Nile2Iter iter = giter(curs(view)); + Nile2Iter enditer = giter(endcurs(view)); + // XXX Checkpoint for undo! + Nile2Iter pt = unit.cut(iter, enditer); + + unit.insertPos(pt, dir, false); + + unit.paste(pt, iter, enditer); + + curs(view).set(iter.getCursor()); + endcurs(view).set(enditer.getCursor()); + } + + /** Tunnel text from one nile window to another. + * The text can be copied or cut. + */ + static public void tunnel(Nile2Unit unit, ZZCell from, ZZCell to, + int dir, boolean copy) { + clearSavedCursor(from); clearSavedCursor(to); + Nile2Iter fiter = giter(curs(from)); + Nile2Iter fenditer = giter(endcurs(from)); + Nile2Iter titer = giter(curs(to)); + Nile2Iter pt = null; + + // XXX Checkpoint for undo! + if(copy) + unit.copy(fiter, fenditer); + else + pt = unit.cut(fiter, fenditer); + + // Insert exactly where we are -- is this o.k.? + // unit.insertPos(titer, dir, true); + + unit.paste(titer, fiter, fenditer); + + curs(to).set(fiter.getCursor()); + endcurs(to).set(fenditer.getCursor()); + + if(!copy) { + unit.start(pt, -1, false); + curs(from).set(pt.getCursor()); + unit.end(pt, 1, true); + endcurs(from).set(pt.getCursor()); + } + } + + static public boolean insert(ZZCell view, String key) { + clearSavedCursor(view); + if(key == null) + return false; + if(key.length() != 1) + return false; + Nile2Iter it = giter(curs(view)); + it.insert(key); + ZZCursor c = it.getCursor(); + curs(view).set(c); + endcurs(view).set(c); + return true; + } + + static public void backspace(Nile2Unit unit, ZZCell view) { + clearSavedCursor(view); + Nile2Iter iter = giter(curs(view)); + if(!unit.insertPos(iter, -1, false)) return; + Nile2Iter enditer = (Nile2Iter)iter.clone(); + if(!unit.end(enditer, 1, false)) return; + Nile2Iter cut = unit.cut(iter, enditer); + if(cut == null) + throw new ZZError("Couldn't cut!"); + setCursor(unit, view, cut.getCursor()); + } + + static public void del(Nile2Unit unit, ZZCell view) { + // XXX if nothing is selected -- delete unit right from ins cursor + unit.cut(giter(curs(view)), giter(endcurs(view))); + } + + static public void breakParagraph(Nile2Unit unit, ZZCell view) { + clearSavedCursor(view); + Nile2Iter it = giter(curs(view)); + it.breakParagraph(); + setCursor(unit, view, it.getCursor()); + } + + static public void traverseTranscopies(ZZCell view, int dir) { + clearSavedCursor(view); + ZZCell c0 = ZZCursorReal.get(view); + ZZCell c = c0.s("d.nile-transcluded"); + if(c == null) { + ZZLogger.log("Could not traverse transcopies because accused cell " + + "IS not transcopied"); + return; + } + ZZCell h0 = c0.h("d.nile-transcluded-split", true); + if(h0 != null) { // jump over splits + while(h0.equals(c.h("d.nile-transcluded-split"))) { + if(c.equals(c0)) + throw new ZZError("XXX! All transcluded cells are " + + "splits of the same cell! HELP!"); + c = c.s("d.nile-transcluded"); + } + } + ZZCursorReal.setOffs(view, 0); + ZZCursorReal.set(view, c); + } + + + + /** Get a whole Nile stream as a string, properly capitalized. + * Converts paragraph breaks (==struct cells) to double newlines.
    + * XXX a) It's no good this calls Nile2View, and it's even worse it does + * *line-breaking* to capitalize! I.e. move capitalization elsewhere + * (ZZUtil)
    + * XXX b) Do this for the text between two iters (a selection), not only + * for a whole stream.
    + * XXX c) Does this belong in this class? (It seemed to fit?) + * + * @param inStream Some cell inside the stream to be read. + */ + static public String stringify(ZZCell inStream) { + ZZCell hd = inStream.h("d.nile"); + Nile1View n1v = new Nile1View(); + n1v.init__zob(); + String s = ""; + ZZCell tail = Nile2Iter.findStruct(hd, 1, false); + while(hd != null) { + FText ft = n1v.paragraph(hd, tail, null, null, null); + ft.capitalize(); + s = s + FText.Part.join(ft.parts); + hd = tail; + if(hd != null) tail = Nile2Iter.findStruct(hd, 1, false); + s = s + "\n\n"; + } + return s; + } + + + + + // Shorthand... + static public ZZCursorReal curs(ZZCell view) { + return new ZZCursorReal(view); + } + static public Nile2Iter giter(ZZCursor c) { + return new Nile2Iter(c); + } + + static public ZZCursorReal endcurs(ZZCell view) { + ZZCell end = view.getOrNewCell("d.nile-sel"); + return new ZZCursorReal(end); + } + +} diff --git a/Modules/nile/Nile2Test.java b/Modules/nile/Nile2Test.java new file mode 100644 index 0000000..19b55cb --- /dev/null +++ b/Modules/nile/Nile2Test.java @@ -0,0 +1,152 @@ +/* +Nile2Test.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag.module; +import org.gzigzag.*; + +/** Some simple tests for Nile. + */ + +public final class Nile2Test { +public static final String rcsid = "$Id: Nile2Test.java,v 1.1 2000/12/07 00:37:19 tjl Exp $"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static final void pok(String id, boolean ok) { + if(ok) p("ok "+id); + else p("not ok "+id); + } + + public static void main(String[] argv) { + ZZSpace z = new ZZDimSpace(); + ZZCell home = z.getHomeCell(); + ZZCell stream = home.N("d.1", 1); + + stream.N("d.nile-struct", 1); // Beginning structural marker + stream = stream.N("d.nile", 1); // Can't be at same cell. + stream.setText("Hello world a! How's it going?"); + + Nile2Iter it = new Nile2Iter(new ZZCursorVirtual(stream, 4)); + + p("Got: "+it.get()); + + Nile2Iter nextpart = it.cut(); + it.dumpStream(); + nextpart.dumpStream(); + + p("Got: "+it.get()); + pok("Atend", it.get() == -1); + pok("Prev", it.get(-1) == 'l'); + + pok("foll", nextpart.get() == 'o'); + pok("atstart", nextpart.get(-1) == -1); + + it.dumpStream(); + p("Joining"); + it.join(nextpart); + + it.dumpStream(); + nextpart.dumpStream(); + + pok("GET1", it.get() == 'o'); + pok("NEXT1", it.next() == ' '); + pok("NEXT2", it.next() == 'w'); + pok("PREV1", it.prev() == ' '); + + // Next, test word boundaries. + + Nile2Unit un = new Nile2Unit.Word(); + pok("PREVWORD1", un.start(it, -1, false)); + pok("PREVWORD2", !un.start(it, -1, false)); + pok("Wordplace", it.get() == 'H' && it.get(1) == 'e'); + + pok("NEXTWORD1", un.start(it, 1, true)); + pok("Wordplace2", it.get() == 'H' && it.get(1) == 'e'); + pok("NEXTWORD2", un.start(it, 1, false)); + pok("Wordplace3", it.get() == 'w' && it.get(1) == 'o'); + pok("NEXTWORD2", un.start(it, 1, false)); + pok("Wordplace2.5", it.get() == 'a' && it.get(1) == '!'); + pok("NEXTWORD2", un.start(it, 1, false)); + pok("Wordplace3", it.get() == '!' && it.get(1) == ' '); + pok("NEXTWORD3", un.start(it, 1, false)); + pok("Wordplace4", it.get() == 'H' && it.get(1) == 'o'); + + + Nile2Unit un2 = new Nile2Unit.Sentence(); + pok("senst1", un2.start(it, -1, false)); + pok("senst2", !un2.start(it, -1, false)); + pok("Sen", it.get() == 'H' && it.get(1) == 'e'); + pok("senst3", un2.start(it, 1, false)); + pok("Sen", it.get() == 'H' && it.get(1) == 'o'); + it.dumpStream(); + pok("senst4", !un2.start(it, 1, false)); + it.dumpStream(); + pok("senst5", un2.start(it, -1, false)); + pok("senst6", un2.start(it, -1, false)); + pok("senst7", !un2.start(it, -1, false)); + // Now at beginning. + Nile2Iter end = (Nile2Iter)it.clone(); + pok("sene1", un2.end(end, 1, true)); + p("At end: "+(end.get(-1))+"||"+end.get()); + end.dumpStream(); + pok("sene2", end.get() == ' ' && end.get(-1) == '!'); + + Nile2Iter result = un2.cut(it, end); + + p("Start:"); + it.dumpStream(); + p("End:"); + end.dumpStream(); + p("Res:"); + result.dumpStream(); + + // Next, test adjustspaces. + + ZZCell n = stream.N("d.1", 1); + n.setText("d"); + it.set(new ZZCursorVirtual(n, 0)); + pok("as1", it.get(-1) == -1 && it.get() == 'd' && it.get(1) == -1); + it.adjustSpaces(0, 1); + p("Adjusted: "); + it.dumpStream(); + pok("as2", it.get(-1) == -1 && it.get() == 'd' && it.get(1) == ' '); + it.adjustSpaces(0, 0); + p("Adjusted3: "); + it.dumpStream(); + pok("as3", it.get(-1) == -1 && it.get() == 'd' && it.get(1) == -1); + it.adjustSpaces(1, 0); + pok("as4", it.get(-1) == -1 && it.get() == ' ' && it.get(1) == 'd' + && it.get(2) == -1); + it.adjustSpaces(0, 0); + p("Adjusted5: "); + it.dumpStream(); + pok("as5", it.get(-1) == -1 && it.get() == 'd' && it.get(1) == -1); + + + + pok("END", true); + System.exit(0); + } + +} diff --git a/Modules/nile/Nile2Unit.java b/Modules/nile/Nile2Unit.java new file mode 100644 index 0000000..fac6b63 --- /dev/null +++ b/Modules/nile/Nile2Unit.java @@ -0,0 +1,432 @@ +/* +Nile2Unit.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag.module; +import org.gzigzag.*; + +/** A nile unit of division. + */ + +public abstract class Nile2Unit { +public static final String rcsid = "$Id: Nile2Unit.java,v 1.5 2000/12/17 16:32:24 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + /** The previous or next position where + * this type of unit may be inserted. + */ + public abstract boolean insertPos(Nile2Iter iter, int dir, + boolean includeThis); + + /** The previous or next beginning position of this type of + * unit. + */ + public abstract boolean start(Nile2Iter iter, int dir, boolean includeThis); + + /** The previous or next ending position of this type of unit. + */ + public abstract boolean end(Nile2Iter iter, int dir, boolean includeThis); + + /** Cut the stream. + * This routine modifies the start and to iterators to point + * to the beginning and end of the modified stream. + * @return The pasted-together cutaway point, from which + * the insert position can be searched with !includeThis. + * + */ + public abstract Nile2Iter cut(Nile2Iter start, Nile2Iter to); + + /** Copy a part of the stream. + * First every cell is spanified, then a new stream with the same spans + * is created. + * This routine modifies the start and to iterators to point + * to the beginning and end of the copied stream. + * XXX any special copying rules to obey, like in cut? + */ + public void copy(Nile2Iter start, Nile2Iter to) { + this.start(start, -1, true); + this.end(to, 1, true); + Nile2Iter.copy(start, to); + } + + public abstract void paste(Nile2Iter at, Nile2Iter what, Nile2Iter whatEnd); + + + static public class Char extends Nile2Unit { + public boolean insertPos(Nile2Iter iter, int dir, + boolean includeThis) { + if(!includeThis) + if(!iter.move(dir)) + if(!iter.shiftPara(dir)) + return false; + return true; + } + public boolean start(Nile2Iter iter, int dir, + boolean includeThis) { + if(!includeThis) + if(!iter.move(dir)) + if(!iter.shiftPara(dir)) + return false; + if(iter.get() == -1) return false; + return true; + } + + public boolean end(Nile2Iter iter, int dir, + boolean includeThis) { + if(!includeThis) + if(!iter.move(dir)) + if(!iter.shiftPara(dir)) + return false; + if(iter.get(-1) == -1) return false; + return true; + } + + public Nile2Iter cut(Nile2Iter start, Nile2Iter to) { + Nile2Iter after = to.cut(); + start.cut(); + start.join(after); + return start; + } + + public void paste(Nile2Iter at, Nile2Iter what, Nile2Iter whatEnd) { + } + } + + + /** The word and sentence base class. + * Words and sentences obey the same rules for the insert point. + */ + static public abstract class WordOrsentence extends Nile2Unit { + public abstract boolean isStart(Nile2Iter iter); + public abstract boolean isEnd(Nile2Iter iter); + public abstract int nspacesAtEnd(); + + // As documented, + // word insert points are word starting points, as well as + // paragraph's ending points. + public boolean insertPos(Nile2Iter iter, int dir, + boolean includeThis) { + return startOrIns(iter, dir, includeThis, true); + } + + public boolean start(Nile2Iter iter, int dir, boolean includeThis) { + return startOrIns(iter, dir, includeThis, false); + } + + public boolean startOrIns(Nile2Iter iter, int dir, boolean includeThis, + boolean insert) { + // This way we can always assume includeThis later. + if(!includeThis) + if(!iter.move(dir)) { + if(!iter.shiftPara(dir)) + return false; + // If we were looking for an insert point, we just + // found it... + if(dir < 0 && insert) return true; + } + // Can optimize if necessary... + while(true) { + if(isStart(iter)) return true; + if(!iter.move(dir)) { + if(dir > 0 && insert) return true; + if(!iter.shiftPara(dir)) return false; + if(dir < 0 && insert) return true; + } + + } + } + + public boolean end(Nile2Iter iter, int dir, boolean includeThis) { + if(!includeThis) + if(!iter.move(dir)) { + if(!iter.shiftPara(dir)) return false; + // In forwards dir, just go to the beginning + // of the next paragraph. + // This way, cutting from the last insertpos until + // end() results in just the paragraph break being + // removed, which is just right. + return true; + } + while(true) { + if(isEnd(iter)) return true; + if(!iter.move(dir)) + if(!iter.shiftPara(dir)) + return false; + } + } + + public Nile2Iter cut(Nile2Iter start, Nile2Iter end) { + // Find first non-space character. + int nws = this.firstNonWs(start); + this.p("Cut Firstnonws: "+nws + " '"+(char)nws+"'"); + boolean startPunct = this.punct(nws); + + // cut all the space after end. + int ncut = 0; + Nile2Iter endclone = (Nile2Iter)end.clone(); + while(this.ws(end.get())) { end.move(1); ncut ++; } + // If we happen to have space before us, count that too! + int nspace = 0; + while(this.ws(endclone.prev())) nspace++; + + Nile2Iter rstart = null; + if(ncut + nspace == 0 || startPunct) { + // If no space at end, + // we must cut space from before this, if it + // is a single space. + if(this.ws(start.get(-1)) && !this.ws(start.get(-2))) + (rstart = (Nile2Iter)start.clone()). move(-1); + else + if(this.ws(start.get(-1)) && startPunct) { + (rstart = (Nile2Iter)start.clone()). move(-1); + // For the if down later + ncut = 1; + } + } + // Now, here's the cut. We take away the stuff from + // start to end and then remove from rstart + // We must cut starting from the end so as not to disturb + // things. + Nile2Iter after = end.cut(); + Nile2Iter first = start.cut(); + Nile2Iter before = (Nile2Iter)start.clone(); + start.set(first); // We want to return this in start. + // Finally, cut the other stuff. + if(rstart != null) { + rstart.cut(); + before = rstart; + } + before.join(after); + // This is a bit special rule. + if(startPunct && ncut + nspace > 0) + before.insertInCell(" "); + return before; + } + + public void paste(Nile2Iter at, Nile2Iter what, Nile2Iter whatEnd) { + // Check whether what has punctuation in the start... + int nws = this.firstNonWs(what); + this.p("Paste Firstnonws: "+nws + " '"+(char)nws+"'"); + boolean startPunct = this.punct(nws); + Nile2Iter after = null; + + if(dbg) { + this.p("PASTE!!!"); + at.dumpStream(); + what.dumpStream(); + } + + + if(startPunct) { + // If there is punctuation, we must start it with + // exactly the spaces that were there, UNLESS + // we are at the beginning of the sentence, in which + // case we shall have two spaces. + + if(this.ws(at.get(-1)) && this.ws(at.get(-2))) { + // Ok, now it's difficult. + // Leave these spaces, but remove one in the + // beginning of + what.adjustSpaceStart(0); + after = at.cut(); + } else { + if(this.ws(at.get(-1))) { + at.move(-1); + after = at.cut(); + after.move(1); + after = after.cut(); + } else { + after = at.cut(); + } + } + } else { + // pasting words is a bit tricky. + int prev = at.get(-1); + int cur = at.get(); + // Where do we want to ensure we have space. + boolean spaceEnd = false, spaceStart = false; + // If we are at start of paragraph, we ensure that + // a space is in the end. + if(prev == -1) spaceEnd = true; + else if(this.punct(cur)) { + // If we are at punctuation, we put a space after + // inserted text is there was a space before. + if(this.ws(prev)) spaceEnd = true; + else spaceStart = true; + } + else spaceEnd = true; + + what.adjustSpaces(spaceStart ? 1 : 0, + spaceEnd ? nspacesAtEnd() : 0); + + + after = at.cut(); + } + at.join(what); + whatEnd.set(what); + whatEnd.streamEnd(1); + whatEnd.join(after); + whatEnd.set(after); + } + } + + static public class Word extends WordOrsentence { + public boolean isStart(Nile2Iter iter) { return this.isWordStart(iter); } + public boolean isEnd(Nile2Iter iter) { return this.isWordEnd(iter); } + public int nspacesAtEnd() { return 1; } + } + + static public class Sentence extends WordOrsentence { + public boolean isStart(Nile2Iter iter) { return this.isSentenceStart(iter); } + public boolean isEnd(Nile2Iter iter) { return this.isSentenceEnd(iter); } + public int nspacesAtEnd() { return 2; } + } + + static public class Paragraph extends Nile2Unit { + // A paragraph may be inserted at the end of any paragraph, + // or in the very beginning of the stream. + // That requires special handling because + // Nile2Iter can't get there. + public boolean insertPos(Nile2Iter iter, int dir, + boolean includeThis) { + // XXX First, check if we *are* there already. + + if(!end(iter, dir, includeThis)) { + if(dir > 0) return false; + ZZCursor curs = iter.getCursor(1); + curs.set(curs.get().h("d.nile")); + curs.setOffs(0); + iter.set(curs); + } + return true; + } + public boolean start(Nile2Iter iter, int dir, boolean includeThis) { + if(!includeThis) { + if(!iter.move(dir)) { + // We were at the beginning + if(!iter.shiftPara(dir)) + return false; + } + } + return iter.paraEnd(-1); + } + public boolean end(Nile2Iter iter, int dir, boolean includeThis) { + if(!includeThis) { + if(!iter.move(dir)) { + // We were at the beginning + if(!iter.shiftPara(dir)) + return false; + } + } + return iter.paraEnd(1); + } + + public Nile2Iter cut(Nile2Iter start, Nile2Iter end) { + return null; + } + public void paste(Nile2Iter at, Nile2Iter what, Nile2Iter whatEnd) { + } + } + + // Something non-ws following to ws's. + static public boolean isSentenceStart(Nile2Iter iter) { + int cur = iter.get(); + if(cur == -1 || ws(cur)) return false; + int prev = iter.get(-1); + if(prev == -1) return true; + if(!ws(prev)) return false; + int prev2 = iter.get(-2); + if(prev2 == -1) return true; + if(!ws(prev2)) return false; + return true; + } + + // Something non-ws following to ws's. + static public boolean isSentenceEnd(Nile2Iter iter) { + int prev = iter.get(-1); + if(prev == -1 || ws(prev)) return false; + int cur = iter.get(); + if(cur == -1) return true; + if(!ws(cur)) return false; + int next = iter.get(1); + if(next == -1) return true; + if(!ws(next)) return false; + return true; + } + + static public boolean isWordStart(Nile2Iter iter) { + int cur = iter.get(); + if(punct(cur)) { +/* if(lett(punct.get(-1)) && lett(punct.get(1))) { + // Punctuation surrounded by two letters is NOT + // a word boundary. + return false; + } else XXX Must test in other cases!!! */ + + return true; + } + + int prev = iter.get(-1); + // This should also cover buffer start. + if(lett(cur) && !lett(prev)) return true; + return false; + } + static public boolean isWordEnd(Nile2Iter iter) { + int prev = iter.get(-1); + if(punct(prev)) +/* + if(lett(punct.get(-2)) && lett(punct.get(0))) { + // Punctuation surrounded by two letters is NOT + // a word boundary. + return false; + } else XXX Must test!!!! */ + return true; + + int cur = iter.get(); + if(lett(prev) && !lett(cur)) return true; + return false; + } + + // Shorthand. + // Exactly one of these must return true for every character. + // except -1, when all are false. + static boolean ws(int c) { return Character.isWhitespace((char)c); } + static boolean punct(int c) { + if(c == -1) return false; + return (!Character.isWhitespace((char)c)) && + (!Character.isLetterOrDigit((char)c)); + } + static boolean lett(int c) { return Character.isLetterOrDigit((char)c); } + + static int firstNonWs(Nile2Iter iter) { + int ch = 0; + // Use index, don't move. + for(int i=0; (ch=iter.get(i)) != -1; i++) { + if(!ws(ch)) return ch; + } + return -1; + } + +} diff --git a/Modules/nile/NileApplet.java b/Modules/nile/NileApplet.java new file mode 100644 index 0000000..fbfb3b8 --- /dev/null +++ b/Modules/nile/NileApplet.java @@ -0,0 +1,63 @@ +/* +NileApplet.java + * + * Copyright (c) 1999, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag; + +import java.awt.*; +import java.applet.*; +import java.io.*; +import java.util.*; + +/** An applet showing the split Nile view. + * This just takes a lot of code from ZZApplet -- bad style. Well, this is + * just an intermediate: When we start making real demos using the Dump + * stuff, ZZApplet probably needs to be rewritten, and NileApplet will be + * totally obsolete. + */ + +public class NileApplet extends Applet { + public static final String rcsid = "$Id: NileApplet.java,v 1.4 2001/01/03 16:47:50 raulir Exp $"; + + public void init() { + ZZSpace space = new ZZCacheDimSpace(new DummyStreamSet()); + ZZCell home=space.getHomeCell(); + home.N("d.1").setText("First text"); + home.N("d.1").setText("Second text"); + + ZZDefaultSpace.create(home); + setLayout(new BorderLayout()); + ZZWindows.init(space,this); + + ZZCell topl = ZZWindows.startCell().s("d.1", 1) + .s("d.2", 1); + ZZCell a = topl.s("d.1", 2); + ZZCell b = topl.s("d.2", 1).s("d.1", 1); + ZZCursorReal.set(a, home.s("d.1", 1)); + ZZCursorReal.set(b, home.s("d.1", 2)); + ZZCursorReal.setColor(a,Color.red); + ZZCursorReal.setColor(b,Color.yellow); + org.gzigzag.module.SplitNileDemo.updateSpace(a, a, b); + + ZZObsTrigger.runObsQueue(); + } +} diff --git a/Modules/nile/NileDemo.java b/Modules/nile/NileDemo.java new file mode 100644 index 0000000..2e34946 --- /dev/null +++ b/Modules/nile/NileDemo.java @@ -0,0 +1,143 @@ +/* +NileDemo.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; +import java.io.*; + + +public class NileDemo { +public static final String rcsid = "$Id: NileDemo.java,v 1.3 2000/12/28 01:19:07 bfallenstein Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + /** Update the bindings etc.in the space. + * This is temporary and should go away once we have better + * space management. + */ + static void updateSpace(ZZCell code, ZZCell viewCell, ZZCell ctrlCell) { + // First, make sure the system list cell is ok + // and recreate actions. + + ZZSpace sp = code.getSpace(); + ZZCell t0 = ZZDefaultSpace.findOnSystemlist(sp, "Nile1", true); + ZZCell bind = t0.getOrNewCell("d.1", 1); + ZZCell rast = t0.getOrNewCell("d.2", 1); + + bind.disconnect("d.1", 1); + bind = bind.N("d.1", 1); + Nile1.actions(bind); + + rast.disconnect("d.1",1); + rast = rast.N("d.1"); + rast.setText("Nile1View"); + rast = rast.N("d.1"); + rast.setText("Nile1.Normal"); + rast = rast.s("d.1", -1); // go to the cell we need + + // Then, update windows. + + ZZCell datac = updateWin(sp, viewCell, rast, bind, false); + ZZCell ctrlc = updateWin(sp, ctrlCell, rast, bind, true); + if(datac != null && ctrlc != null) { + datac.excise("d.nile-wins"); ctrlc.excise("d.nile-wins"); + ctrlc.connect("d.nile-wins", 1, datac); + datac.connect("d.nile-wins", 1, ctrlc); + } + } + + static ZZCell updateWin(ZZSpace sp, ZZCell viewCell, ZZCell rast, + ZZCell bind, boolean ctrl) { + if(viewCell == null) return null; + + // Make sure we have a window and update its + // binding and raster. + + ZZCell win = null; + String title = ctrl ? "Nile1-Left" : "Nile1W"; + int round = 0; + while(win == null) { + if(round > 1) + throw new ZZError("Couldn't create window"); + round++; + + win = ZZDefaultSpace.findOnSystemlist(sp, "Windows", false); + win = win.s("d.1"); + win = win.findText("d.2", 1, title); + + if(win == null) + ZZDefaultSpace.newToplevelView(sp, + title, ctrl ? 0 : 400, 20, 400, 400, + null, null, null, viewCell, + null, new Color(0x819fff)); + } + + // Then, set window bindings + win = win.s("d.1", 2); + ZZCell bcurs = win.getOrNewCell("d.bind", 1); + ZZCursorReal.set(bcurs, bind); + ZZCell viewsel = win.findText("d.2", 1, "View"); + ZZCursorReal.set(viewsel, rast); + ZZCursorReal.setColor(viewsel, ZZUtil.perturb(Color.red)); + return win; + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + ZZUpdateManager.setFast(view); + + ZZCell viewCell = view.getViewcell(); + ZZCell otherCell = viewCell.s("d.nile-wins"); + + p("Nile action: "+id+" "+key); + + StringTokenizer st = new StringTokenizer(id); + String[] toks = new String[st.countTokens()]; + for(int i=0; i 1) + throw new ZZError("Couldn't create window"); + round++; + + win = ZZDefaultSpace.findOnSystemlist(sp, "Windows", false); + win = win.s("d.1"); + win = win.findText("d.2", 1, title); + + if(win == null) + ZZDefaultSpace.newToplevelView(sp, + title, 20, 20, 600, 400, + null, null, null, null, + null, new Color(0x819fff)); + } + + // Then, create the cursor pair and set the window cursor + win = win.s("d.1", 2); + ZZCell leftcurs = win.N(); + ZZCursorReal.attach(leftcurs, ctrlCell); + ZZCell rightcurs = leftcurs.N("d.nile-pair"); + ZZCursorReal.attach(rightcurs, viewCell); + ZZCursorReal.set(win, leftcurs); + + // Finally, set window bindings + ZZCell bcurs = win.getOrNewCell("d.bind", 1); + ZZCursorReal.set(bcurs, bind); + ZZCell viewsel = win.findText("d.2", 1, "View"); + ZZCursorReal.set(viewsel, rast); + ZZCursorReal.setColor(viewsel, ZZUtil.perturb(Color.red)); + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + ZZUpdateManager.setFast(view); + + // Update the Nile stuff to the latest bindings (defined + // unfortunately in this file -- oh how I long for the day + // when they are in a ZZ space as the definitive version) + if(id.equals("UPDATE")) { + updateSpace(code, view.getViewcell(), cview.getViewcell()); + } + } + }; +} diff --git a/Modules/nile/SplitNileView.zob b/Modules/nile/SplitNileView.zob new file mode 100644 index 0000000..536fdb0 --- /dev/null +++ b/Modules/nile/SplitNileView.zob @@ -0,0 +1,71 @@ +/* +SplitNileView.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; + +/** A view that shows two Nile streams side-by-side. */ + +public class SplitNileView implements FlobView, ZOb { +public static final String rcsid = "$Id: SplitNileView.zob,v 1.1 2000/12/26 20:15:50 bfallenstein Exp $"; + /** Should we print out debugging info? */ + public static boolean dbg = false; + static final void p(String s) { if(dbg) pa(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + /** The space to leave between the two Nile streams. */ + int margin + = 20; + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell win, String[] dims, ZZCell accursed) { + ZZCell leftc = accursed.s("d.nile-pair", -1); + ZZCell rightc = accursed.s("d.nile-pair"); + if(leftc != null && rightc == null) + rightc = accursed; + else if(leftc == null && rightc != null) + leftc = accursed; + else + throw new ZZError("HELP! Strange d.nile-pair arrangement XXX"); + + ZZCell leftacc = ZZCursorReal.get(leftc); + ZZCell rightacc = ZZCursorReal.get(rightc); + + Dimension size = new Dimension(into.getSize()); + size.width = (size.width - margin) / 2; + FlobSet left = into.create(size), right = into.create(size); + + Nile1View view = new Nile1View(); + view.init__zob(); + SimpleBeamer bmr = new SimpleBeamer(); + + view.raster(left, fact, leftc, dims, leftacc); + view.raster(right, fact, rightc, dims, rightacc); + + into.fetch(left, 0, 0, 0); + into.fetch(right, size.width + margin, 0, 0); + + bmr.decorate(into, "", null); + } +} diff --git a/Modules/nile/draft/Nile3Ops.java b/Modules/nile/draft/Nile3Ops.java new file mode 100644 index 0000000..4738cdd --- /dev/null +++ b/Modules/nile/draft/Nile3Ops.java @@ -0,0 +1,166 @@ +/* +Nile3Ops.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +/** A library of routines for operating on Nile streams. + * @see Nile1 + */ + +public abstract class Nile3Ops { +public static final String rcsid = "$Id: Nile3Ops.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + static public void saveCursor(ZZCell win) { + ZZCell s = win.getOrNewCell("d.nile-save", 1); + if(ZZCursorReal.get(s) == null) + ZZCursorReal.set(s, new ZZCursorReal(win)); + } + static public void clearSavedCursor(ZZCell win) { + ZZCell s = win.getOrNewCell("d.nile-save", 1); + if(ZZCursorReal.get(s) != null) + ZZCursorReal.set(s, (ZZCell)null); + } + static public ZZCursor getSavedCursor(ZZCell win) { + ZZCell s = win.getOrNewCell("d.nile-save", 1); + return new ZZCursorReal(s); + } + + static public void setCursor(Nile3Unit unit, ZZCell win, ZZCursor to) { + Nile3Pos pos = new Nile3Pos(to); + setPart(win, unit.extend(pos)); + } + + static public void moveCursor(Nile3Unit unit, ZZCell win, int dir) { + Nile3Part part = getPart(win); + if(!unit.step(part, dir)) return; + setPart(win, part); + } + + static public void adjust(Nile3Unit unit, ZZCell win, int end, int dir) { + Nile3Part part = getPart(win); + if(!unit.adjust(part, end, dir)) return; + setPart(win, part); + } + + static public void hop(Nile3Unit unit, ZZCell win, int dir) { + Nile3Part part = getPart(win); + Nile3Pos pos = part.side(dir); + if(!unit.insertPos(pos, dir, part, false)) return; + unit.move(part, pos, false); + setPart(win, part); + } + + /** Tunnel text from one nile window to another. + * The text can be copied or cut. + */ + static public void tunnel(Nile3Unit unit, ZZCell from, ZZCell to, + boolean copy) { + Nile3Part part = getPart(from); + Nile3Pos pos = getPart(to).start; + if(!unit.insertPos(pos, -1, part, true)) return; + unit.move(part, pos, copy); + setPart(to, part); + } + + static public boolean insert(ZZCell win, String key) { + if(key == null) + return false; + if(key.length() != 1) + return false; + Nile3Pos pos = getPart(win).start; + pos.insert(key, 1); + setPos(win, pos); + return true; + } + + static public void backspace(Nile3Unit unit, ZZCell win) { + Nile3Part orig = getPart(win); + Nile3Part part = new Nile3Part(orig.start, orig.start); + unit.edge(part.start, -1, -1, false); + unit.edge(part.end, 1, -1, true); + unit.cut(part); + } + + static public void del(Nile3Unit unit, ZZCell win) { + Nile3Pos pos = unit.cut(getPart(win)); + setPos(win, pos); + } + + static public void breakParagraph(Nile3Unit unit, ZZCell win) { + Nile3Part part = getPart(win); + part.start.breakParagraph(); + } + + + /** Get a whole Nile stream as a string, properly capitalized. + * Converts paragraph breaks (==struct cells) to double newlines.
    + * XXX a) It's no good this calls Nile1View.
    + * XXX b) Do this for a Nile3Part (a selection), not only + * for a whole stream.
    + * XXX c) Does this belong in this class? (It seemed to fit?) + * + * @param inStream Some cell inside the stream to be read. + */ + static public String stringify(ZZCell inStream) { + ZZCell hd = inStream.h("d.nile"); + Nile1View n1v = new Nile1View(); + n1v.init__zob(); + String s = ""; + ZZCell tail = Nile2Iter.findStruct(hd, 1, false); + while(hd != null) { + FText ft = n1v.paragraph(hd, tail, null, null, null); + ft.capitalize(); + s = s + FText.Part.join(ft.parts); + hd = tail; + if(hd != null) tail = Nile2Iter.findStruct(hd, 1, false); + s = s + "\n\n"; + } + return s; + } + + // Shorthand... + static public Nile3Part getPart(ZZCell win) { + ZZCursorReal start = new ZZCursorReal(win); + if(start.getOffs() == start.NO_OFFSET) + start = new ZZCursorReal(win.getOrNewCell("d.nile-save")); + ZZCursorReal end = new ZZCursorReal(win.getOrNewCell("d.nile-sel")); + return new Nile3Part(start, end); + } + + static public void setPart(ZZCell win, Nile3Part part) { + ZZCursor start = part.start.get(), end = part.end.get(); + ZZCursorReal.set(win, start.get()); + // if(ZZCursorReal.getOffs(win) != ZZCursorReal.NO_OFFSET) + ZZCursorReal.setOffs(win, start.getOffs()); + ZZCursorReal.set(win.getOrNewCell("d.nile-save"), start); + ZZCursorReal.set(win.getOrNewCell("d.nile-sel"), end); + } + + static public void setPos(ZZCell win, Nile3Pos pos) { + setPart(win, new Nile3Part(pos, pos)); + } +} diff --git a/Modules/nile/draft/Nile3Part.java b/Modules/nile/draft/Nile3Part.java new file mode 100644 index 0000000..77ade00 --- /dev/null +++ b/Modules/nile/draft/Nile3Part.java @@ -0,0 +1,132 @@ +/* +Nile3Part.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag.module; +import org.gzigzag.*; + +/** A Nile span, with a start and an end. + * This object explicitly assumes no modifications to the + * stream while it is working. + */ + +public final class Nile3Part implements Cloneable { +public static final String rcsid = "$Id: Nile3Part.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $"; + public static boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + public final Nile3Pos start = new Nile3Pos(); + public final Nile3Pos end = new Nile3Pos(); + + public Nile3Part(Nile3Pos start, Nile3Pos end) { + this.start.set(start); this.end.set(end); + check(); + } + public Nile3Part(ZZCursor start, ZZCursor end) { + p(start + " " + end); + this.start.set(start); this.end.set(end); + check(); + } + + public Nile3Pos side(int dir) { + if(dir < 0) return start; + else return end; + } + + public Nile3Pos cut() { + if(isStream()) + return null; // XXX should this throw an error? + check(); + start.split(false, 1); + end.split(false, -1); + Nile3Pos before = (Nile3Pos)start.clone(); + Nile3Pos after = (Nile3Pos)end.clone(); + if(!before.bias(-1) || !after.bias(1)) + throw new ZZError("HELP! End of stream after split! XXX"); + start.c.disconnect("d.nile", -1); + end.c.disconnect("d.nile", 1); + before.c.connect("d.nile", 1, after.c); + return before; + } + + /** Make a cell's content into a span. */ + static public Span spanify(ZZCell c0) { + Span sp = c0.getSpan(); + if(sp != null) return sp; + + StringScroll sc = c0.getSpace().getStringScroll(); + String s = c0.getText(); + long soffs = sc.append(s); + sp = Span.create( + Address.scrollOffs(sc, soffs), + Address.scrollOffs(sc, soffs + s.length() - 1) + ); + c0.setSpan(sp); + return sp; + } + + public Nile3Part copy() { + check(); + start.split(false, 1); + end.split(false, -1); + ZZCell c = start.c; + ZZCell first = c.N(), last = first; + while(true) { + last.setSpan(spanify(c)); + if(c.equals(end.c)) break; + c = c.s("d.nile"); + last = last.N("d.nile"); + } + return new Nile3Part( + new ZZCursorVirtual(first, 0), + new ZZCursorVirtual(last, last.getText().length())); + } + + /** Return true if there's nothing before or after this. */ + public boolean isStream() { + return start.end(-1) && end.end(1); + } + + /** Check the integrity of this Nile3Part: start <= end? */ + public void check() { + boolean good = true; + if(start.c.equals(end.c)) { + good = start.offs <= end.offs; + p(start.offs + " " + end.offs); + } else { + good = start.c.findCell("d.nile", 1, end.c); + p(start.c + " " + end.c); + } + if(!good) + throw new ZZError("Malformed Nile3Part stream! XXX"); + } + + public Object clone() { + try { + return super.clone(); + } catch(CloneNotSupportedException e) { + ZZLogger.exc(e); + return null; + } + } +} \ No newline at end of file diff --git a/Modules/nile/draft/Nile3Pos.java b/Modules/nile/draft/Nile3Pos.java new file mode 100644 index 0000000..26381fa --- /dev/null +++ b/Modules/nile/draft/Nile3Pos.java @@ -0,0 +1,338 @@ +/* +Nile3Pos.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; + +/** A character-level iterator object that knows about + * paragraphs for a Nile stream. + * This object explicitly assumes no modifications to the + * stream while it is working. + * The position is between the characters, not on a character. + * Actually, it is between (a char | a para boundary) and + * (a char | a para boundary), i.e., it can be at the beginning or end + * of a para or between two paras. + */ + +public final class Nile3Pos implements Cloneable { +public static final String rcsid = "$Id: Nile3Pos.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + /** Returned by type() or read(), this denotes end/beginning of stream. */ + public static final int END = -1; + /** Returned by type() or read(), this denotes a paragraph break. */ + public static final int PARA = -2; + /** Returned by type(), this means punctuation. */ + public static final int PUNCT = -3; + /** Returned by type(), this means alphanumeric character. */ + public static final int ALPHA = -4; + /** Returned by type(), this means whitespace. */ + public static final int WS = -5; + /** Returned by read(), this means special thing (to type, it's PUNCT). */ + public static final int SPECIAL = -6; + + ZZCell c; + int offs; + + // Cache these for speed. + // Note: ctxt and cspan are only valid if NOT (isStruct || isSpecial)! + int clen; + String ctxt; + Span cspan; + + // Is this cell a struct cell, a text object? + private boolean isStruct, isSpecial; + + public Nile3Pos(Nile3Pos pos) { set(pos); } + public Nile3Pos(ZZCursor pos) { set(pos); } + Nile3Pos() {} + + public ZZCursor get() { return new ZZCursorVirtual(c, offs); }; + + + private void load(ZZCell c) { + this.c = c; + isStruct = (c.s("d.nile-struct", 1) != null); + isSpecial = (c.s("d.nile-special", 1) != null); + + if(isStruct || isSpecial) + clen = 1; + else { + ctxt = c.getText(); + cspan = c.getSpan(); + clen = ctxt.length(); + } + } + + public void set(Nile3Pos pos) { + load(pos.c); + offs = pos.offs; + } + public void set(ZZCursor pos) { + load(pos.get()); + offs = pos.getOffs(); + if(offs == pos.NO_OFFSET) offs = 0; + } + + /** Internal convenience: try to insert with bias, if can't, return */ + private boolean insert(String s, int side, int bias) { + if(!bias(bias)) return false; + if(cspan != null) return false; + + c.setText(ctxt.substring(0, offs) + s + ctxt.substring(offs)); + ZZCursorReal.adjustCursors(c, offs, s.length()); + if(side > 0) offs += s.length(); + return true; + } + + public void insert(String s, int side) { + if(insert(s, side, 1)) return; + if(offs == 0) + if(insert(s, side, -1)) return; + split(false, 1); + load(c.N("d.nile", -1)); + c.setText(s); + offs = (side < 0) ? (0) : (clen); + } + + public void insert(Nile3Part what, int side) { + if(!what.isStream()) + throw new ZZError("Can't insert non-stream Nile3Part!"); + split(false, side); + ZZCell other = c.s("d.nile", -side); + c.disconnect("d.nile", -side); + c.connect("d.nile", -side, what.side(side).c); + other.connect("d.nile", side, what.side(-side).c); + } + + public boolean delete(int bias) { + // First, ensure we are in the same cell as the character to delete. + if(!bias(bias)) return false; + + // Then, a special case check (also for isStruct and isSpecial cells) + if(clen == 1) { + ZZCell from = c; + if(c.s("d.nile") != null) { + load(c.s("d.nile")); + offs = 0; + } else if(c.s("d.nile", -1) != null) { + load(c.s("d.nile", -1)); + offs = clen; + } else { + load(c.N("d.nile")); + offs = 0; + } + Enumeration e = ZZCursorReal.getPointers(from); + while(e.hasMoreElements()) { + ZZCell curs = (ZZCell)e.nextElement(); + ZZCursorReal.setcursor(curs, c); + if(ZZCursorReal.getOffs(curs) != ZZCursorReal.NO_OFFSET) + ZZCursorReal.setOffs(curs, offs); + } + from.delete(); + return true; + } + + if(cspan == null) { + if(bias < 0) offs--; + c.setText(ctxt.substring(0, offs) + ctxt.substring(offs)); + ZZCursorReal.adjustCursors(c, offs, -1); + } else { + split(false, bias); + if(bias > 0) c.setSpan(cspan.subSpan(1)); + else c.setSpan(cspan.subSpan(0, clen-1)); + } + load(c); + return true; + } + + /** Split at the current position. + * The original cell will remain the first. + * If side is greater than zero, this pos will be set to the second cell; + * if side is less than zero, this pos will be set to the first cell. + * If offs is zero or equal to the number of characters in c, nothing is + * done and either the current cell or the next cell is returned. + *

    + * The most special case involves doing this at the very end of the stream, + * in which case an empty new cell is created and returned. + * @param side The side of the split to make this Nile3Pos point to. + * @param always Whether to split even if the offset is at the beginning + * or end of a cell. Used e.g. for inserting a paragraph. + */ + public void split(boolean always, int side) { + if(always) { + ZZCell c1 = c.N("d.nile"); + if(cspan == null) { + c.setText(ctxt.substring(0, offs)); + c1.setText(ctxt.substring(offs)); + } else { + c.setSpan(cspan.subSpan(0, offs)); + c1.setSpan(cspan.subSpan(offs)); + } + Enumeration e = ZZCursorReal.getPointers(c); + while(e.hasMoreElements()) { + ZZCell p = (ZZCell)e.nextElement(); + int poffs = ZZCursorReal.getOffs(p); + if(poffs != ZZCursorReal.NO_OFFSET && poffs > offs) { + ZZCursorReal.setcursor(p, c1); + ZZCursorReal.setOffs(p, poffs-offs); + } + } + if(side > 0) { load(c1); offs = 0; } + } else { + if(offs == 0) { + if(side < 0) { + load(c.getOrNewCell("d.nile", -1)); + offs = clen; + } + } else if(offs >= clen) { + if(side > 0) { + load(c.getOrNewCell("d.nile")); + offs = 0; + } + } else + split(true, side); + } + } + + public int type(int dir) { + int ch = read(dir); + if(ch < 0) return ch; + if(Character.isLetterOrDigit((char)ch)) return ALPHA; + if(Character.isWhitespace((char)ch)) return WS; + return PUNCT; + } + /** Return true if type() would return Nile3Pos.END. */ + public boolean end(int dir) { + return type(dir) == END; + } + /** Return true if type() would return Nile3Pos.PARA. */ + public boolean para(int dir) { + return type(dir) == PARA; + } + /** Return true if type() would return Nile3Pos.PUNCT. */ + public boolean punct(int dir) { + return type(dir) == PUNCT; + } + /** Return true if type() would return Nile3Pos.ALPHA. */ + public boolean alpha(int dir) { + return type(dir) == ALPHA; + } + /** Return true if type() would return Nile3Pos.WS. */ + public boolean ws(int dir) { + return type(dir) == WS; + } + /** Return true if boundary, i.e. if end() or para() would return true. */ + public boolean boundary(int dir) { + int t = type(dir); + return (t == END) || (t == PARA); + } + /** Return true if boundary() or ws() would test true. */ + public boolean bws(int dir) { + int t = type(dir); + return (t == WS) || (t == END) || (t == PARA); + } + + /** Read character in given direction. */ + public int read(int dir) { + if(!bias(dir)) return END; + if(isStruct) return PARA; + if(isSpecial) return SPECIAL; + return ctxt.charAt((dir < 0) ? (offs - 1) : (offs)); + } + + /** Move n characters forwards or backwards. + * If the offset given is out of bounds, moves as far as possible + * and returns false, otherwise returns true. In general, this moves as + * little as possible, i.e. if n was positive, bias is negative, and if + * n was negative, bias is positive after call. + */ + public boolean move(int n) { + n += offs; + offs = 0; + + while(n > clen) { + n -= clen; + ZZCell nc = c.s("d.nile"); + if(nc == null) { + // End of stream! + offs = clen; + if(n > 0) return false; + return true; + } + load(nc); + } + while(n < 0) { + ZZCell nc = c.s("d.nile", -1); + if(nc == null) { + offs = 0; + return false; + } + load(nc); + n += clen; + } + + offs = n; + return true; + } + /** (Convenience:) Move if doMove is true. + * This is used by Nile3Unit to make includeThis code simpler. + */ + public boolean move(boolean doMove, int n) { + if(doMove) return move(n); + else return true; + } + + /** Ensure bias in a given direction. + * This means that after bias(1), we are in the cell that contains the + * character in positive direction, and after bias(-1), same in negative + * direction.
    + * If we bump on the end of the stream, return false, else return true. + */ + boolean bias(int dir) { + if(offs + dir >= 0 && offs + dir <= clen) return true; + do { + ZZCell nc = c.s("d.nile", dir); + if(nc == null) return false; + load(nc); + } while(clen == 0); + return true; + } + + public void breakParagraph() { + split(false, 1); + c.N("d.nile", -1).N("d.nile-struct").setText("P"); + } + + public Object clone() { + try { + return super.clone(); + } catch(CloneNotSupportedException e) { + ZZLogger.exc(e); + return null; + } + } +} \ No newline at end of file diff --git a/Modules/nile/draft/Nile3Unit.java b/Modules/nile/draft/Nile3Unit.java new file mode 100644 index 0000000..9146e28 --- /dev/null +++ b/Modules/nile/draft/Nile3Unit.java @@ -0,0 +1,305 @@ +/* +Nile3Unit.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein, based on Nile2Unit by Tuomas Lukka + */ + +package org.gzigzag.module; +import org.gzigzag.*; + +/** A nile unit of division. + * Spaces between units may be non-zero-width. Units may be zero-width, if + * neighbouring units are separated by non-zero spaces. + */ + +public abstract class Nile3Unit { +public static final String rcsid = "$Id: Nile3Unit.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + public static class Char extends Nile3Unit { + public boolean isEdge(Nile3Pos pos, int dir) { + return !pos.boundary(dir); + } + } + + public static class Word extends Nile3Unit { + /** An alphanumeric word. */ + static final int AWORD = 1; + /** A punctuation word, e.g. a smilie. */ + static final int PWORD = 2; + /** An A- or PWORD. */ + static final int WORD = AWORD | PWORD; + /** A piece of left-bound punctuation, like commas. */ + static final int LPUNCT = 4; + /** A piece of right-bound punctuation, like opening brackets. */ + static final int RPUNCT = 8; + /** A piece of left- or right-bound punctuation. */ + static final int BPUNCT = LPUNCT | RPUNCT; + /** A paragraph boundary or the end of the stream. */ + static final int BOUNDARY = 16; + + /** Not a correct combination of words. */ + static final int BAD = 0; + /** Correct combination iff no space in between. */ + static final int NSP = 1; + /** Correct combination iff space in between. */ + static final int SP = 2; + + /** The type of a joining position. */ + public static final int jointype(int lefttype, int righttype) { + if(lefttype & WORD > 0 && righttype & WORD > 0) + return SP; + else if(lefttype == AWORD && righttype == LPUNCT) + return NSP; + else if(lefttype == AWORD && righttype == RPUNCT) + return SP; + else if(lefttype == RPUNCT && righttype == AWORD) + return NSP; + else if(lefttype == LPUNCT && righttype == AWORD) + return SP; + else if(lefttype & BPUNCT > 0 && righttype == lefttype) + return NSP; + else if(lefttype == LPUNCT && righttype == RPUNCT) + return SP; + else if(lefttype == BOUNDARY && righttype == BOUNDARY) + return NSP; + else if(lefttype == BOUNDARY && righttype & WORD > 0) + return NSP; + else if(lefttype & WORD > 0 && righttype == BOUNDARY) + return NSP; + else if(lefttype == LPUNCT && righttype == BOUNDARY) + return NSP; + else if(lefttype == BOUNDARY && righttype == RPUNCT) + return NSP; + else + return BAD; + } + + /** Find out the types of the words next to a word boundary. + * This may only be called on what is known to be a word boundary. + * Else, its behavior is undefined. + */ + public static final int[] wordtype(Nile3Pos pos, int dir) { + int[] res = new int[2]; + + int lch = pos.type(-1), rch = pos.type(1); + boolean lp = pos.punct(-1), rp = pos.punct(1); + Nile3Pos lpos, rpos; + if(lp) { + lpos = (Nile3Pos)pos.clone(); + while(lpos.punct(-1)) lpos.move(-1); + } + if(rp) { + rpos = (Nile3Pos)pos.clone(); + while(rpos.punct(1)) rpos.move(1); + } + + if(!lp && !rp) { + if(pos. + } + + public void cleanJoin(Nile3Pos pos, int lefttype, int righttype) { + int type = jointype(lefttype, righttype); + if(jointype == NSP) { + while(pos.ws(-1)) pos.delete(-1); + while(pos.ws(1)) pos.delete(1); + } else if(jointype == SP) { + if(!pos.ws(-1) && !pos.ws(1)) pos.insert(" ", 1); + } else { + p("Nile3Unit.Word: Detected bad joining in cleanJoin"); + } + } + + public boolean isEdge(Nile3Pos pos, int dir) { + if(pos.punct(-dir)) return true; + if(pos.bws(dir) && pos.alpha(-dir)) return true; + return false; + } + + /** Can what be inserted at pos? */ + public boolean isInsertPos(Nile3Pos pos, Nile3Part what) { + if(!pos.boundary(1) && !isEdge(pos, -1)) return false; + if(what.start.punct(1) && !what.start.bws(-1)) { + } + if(what.end.punct(-1) && !what.end.bws(1)) { + if( + } + if(jointype(pos.-1, what.start.1) == BAD) return false; + if(jointype(pos.1, what.end.-1) == BAD) return false; + } + } + + public static class Sentence extends Nile3Unit { + public boolean isEdge(Nile3Pos pos, int dir) { + if(pos.ws(dir)) return false; + if(pos.boundary(-dir)) return true; + if(!pos.move(-dir)) return false; + if((pos.bws(-dir)) && pos.ws(dir)) return true; + pos.move(dir); + return false; + } + } + + // Ugh! Paragraph is *inefficient*! + // XXX is this a problem? in very long paragraphs maybe? + public static class Paragraph extends Nile3Unit { + public boolean isEdge(Nile3Pos pos, int dir) { + return pos.boundary(-dir); + } + } + + + public boolean step(Nile3Part part, int n) { + int abs = (n < 0) ? (-n) : (n); + int dir = (n < 0) ? (-1) : (1); + Nile3Pos pos = part.side(dir), other = part.side(-dir); + for(int i=0; i 0 ? 10 : -10; } + else if(dy == 0) { ax = dx > 0 ? 10 : -10; ay = 0; } + else { + double raise = dy / (double)dx; + ax = (int)Math.sqrt(100/(raise*raise+1)); + if(dx < 0) ax = -ax; + ay = (int)(raise*ax); + } + + fact.centerFlob(into, links[i].to, links[i].to, 1, p, 0, 0, 1); + lb.l(lx, ly, p.x, p.y); + + if(links[i].dir < 0) + ab.ar(mx+ax, my+ay, mx-ax, my-ay); + else if(links[i].dir > 0) + ab.ar(mx-ax, my-ay, mx+ax, my+ay); + + if(dpt < maxdepth) + part(into, fact, links[i].to, links[i].link, x0, y0, dpt+1, + p.x, p.y, arc, arc+arcd, xd, yd, false); + } + + lb.endl(); + ab.endl(); + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + Dimension size = into.getSize(); + int x0 = size.width/2, xd = size.width / (2 * maxdepth); + int y0 = size.height/2, yd = size.height / (2 * maxdepth); + fact.centerFlob(into, accursed, accursed, 1, + new Point(x0, y0), 0, 0, 1); + part(into, fact, accursed, null, x0, y0, 1, x0, y0, + -Math.PI/2, (Math.PI/2)*3, xd, yd, true); + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + if(id.equals("NEW")) { + ZZCell vc = view.getViewcell(); + ZZCell c = ZZCursorReal.get(vc).N(dim1).N(dim2, -1); + ZZCursorReal.set(vc, c); + } else if(id.equals("CNCT")) { + ZZCell vc = view.getViewcell(); + ZZCell acc = ZZCursorReal.get(vc); + ZZCell[] marks = vc.readRank("d.mark", 1, false); + for(int i=0; i +#include +#include +#include +// #include +#include + +extern "C"{ +#include "jni.h" +} +#include "fi_iki_lukka_ZZOpenGLGraphics.h" + +#include "gltt/FTEngine.h" +#include "gltt/FTFace.h" +#include "gltt/FTInstance.h" +#include "gltt/FTGlyph.h" +#include "gltt/FTGlyphBitmap.h" +#include "gltt/FTGlyphPixmap.h" +#include "gltt/FTBitmapFont.h" +#include "gltt/GLTTBitmapFont.h" +#include "gltt/GLTTPixmapFont.h" +#include "gltt/GLTTOutlineFont.h" +#include "gltt/GLTTFont.h" +#include "gltt/GLTTGlyphPolygonizer.h" +#include "gltt/GLTTGlyphTriangulator.h" + + + +#include +#include +#include +#include +#include +#include + + + +/*********************************************** + * useful little macros + ************************************************/ +#define GET_THIS() jclass zzthis = env->GetObjectClass( obj ); +#define FIELD_ID(_name, _sig) env->GetFieldID( zzthis, _name, _sig) +#define SET_INT_FIELD(_name, _value) \ + env->SetIntField( obj, FIELD_ID(_name, "I"), _value) +#define GET_INT_FIELD(_name) env->GetIntField( obj, FIELD_ID(_name, "I")) + +/****************************************************** + * GLOBALS + ******************************************************/ +/* these will be in java class */ +Display *disp; +Window win; +/***/ +GLboolean db = GL_TRUE; /* doublebuffering */ +GLint disp_list = 0; +XSizeHints sizeHints = { 0 }; +XEvent event; + +GLuint base; + +int args[] = { GLX_DOUBLEBUFFER, + GLX_RGBA, + GLX_DEPTH_SIZE, + 16, + None }; + +void makeRasterFont(Display *dpy) +{ + XFontStruct *fontInfo; + Font id; + unsigned int first, last; + fontInfo = XLoadQueryFont(dpy, + "-*-courier-medium-r-normal-*-*-100-*-*-m-*-iso8859-1"); + + + if (fontInfo == NULL) { + printf ("no font found\n"); + exit (0); + } + + id = fontInfo->fid; + first = fontInfo->min_char_or_byte2; + last = fontInfo->max_char_or_byte2; + + base = glGenLists(last+1); + + if (base == 0) { + printf ("out of display lists\n"); + + exit (0); + } + + glXUseXFont(id, first, last-first+1, base+first); + +} + +/****************************************************** + * printString + ******************************************************/ +void printString(const char *s) +{ + glListBase(base); + glCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned char *)s); +} + + + + +/****************************************************** + * getColormap + ******************************************************/ +Colormap getColormap ( XVisualInfo *vis){ + Status stat; + XStandardColormap *sCm; + Colormap cm; + int i; + int numCmaps; + + if ( vis->c_class != TrueColor ){ + printf ("No support for TrueColor!"); + exit(1); + } + + stat = XmuLookupStandardColormap(disp, vis->screen, vis->visualid, + vis->depth,XA_RGB_DEFAULT_MAP, False, True); + if (stat == 1) { + stat = XGetRGBColormaps( disp, RootWindow(disp, vis->screen), + &sCm, &numCmaps, + XA_RGB_DEFAULT_MAP); + if (stat == 1) + for( i = 0; i < numCmaps; i++ ) + if( sCm[i].visualid == vis->visualid) { + cm = sCm[i].colormap; + XFree(sCm); + return cm; + } + } + + cm = XCreateColormap (disp, RootWindow(disp,vis->screen), + vis->visual, AllocNone); + return cm; +} + + +/****************************************************** + * openWindow + ******************************************************/ +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_openWindow( JNIEnv *env, + jobject obj, + jint width, + jint height) +{ + + XVisualInfo *vi; + Colormap cm; + XSetWindowAttributes xswa; + XWMHints *wmHints; + Atom wmDeleteWindow; + GLXContext cx; + char *display = NULL; + + + /** connect to X server **/ + disp = XOpenDisplay(display); + // FIX ME + if ( disp == NULL ) exit(1); + printf("__C__: openWindow\n"); + /** check for glx */ + if ( ! glXQueryExtension(disp, NULL, NULL)) + // maybe should use some constants + return;// 2; + + /** visual & colormap **/ + vi = glXChooseVisual(disp, DefaultScreen(disp),args ); + if ( ! vi ){ + // no doublebuffering + vi = glXChooseVisual(disp, DefaultScreen(disp),&args[1] ); + if ( ! vi ) exit(1); + db = GL_FALSE; + } + + cm = getColormap(vi); + + /** GL rendering context **/ + cx = glXCreateContext(disp, vi, NULL, GL_TRUE); + if ( cx == NULL ) + exit(1); + + /* some hints etc */ + xswa.colormap = cm; + xswa.border_pixel = 0; + xswa.event_mask = ExposureMask|ButtonPressMask|KeyPressMask; + sizeHints.width = width; + sizeHints.height = height; + sizeHints.x = 10; + sizeHints.y = 10; + + win = XCreateWindow(disp, RootWindow(disp,vi->screen), + sizeHints.x, sizeHints.y, + width, height, 0, vi->depth, InputOutput, + vi->visual, CWEventMask|CWBorderPixel|CWColormap, &xswa); + + wmDeleteWindow = XInternAtom(disp, "WM_DELETE_WINDOW", False); + XSetWMProtocols(disp, win, &wmDeleteWindow,1); + XSetStandardProperties(disp, win, "test", "Testi", + None, None, None, &sizeHints); + + wmHints = XAllocWMHints(); + wmHints->initial_state = NormalState; + wmHints->flags = StateHint; + XSetWMHints(disp, win, wmHints); + + /* bind context to window */ + glXMakeCurrent(disp, win, cx); + + glEnable ( GL_DEPTH_TEST ); + glEnable ( GL_ALPHA_TEST ); + glDisable ( GL_DITHER ); + glDisable ( GL_LIGHTING ); + glDisable ( GL_FOG ); + + glDisable ( GL_TEXTURE_2D ); + + glDisable ( GL_CULL_FACE ); + glDisable ( GL_SCISSOR_TEST ); + glDisable ( GL_STENCIL_TEST ); + + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + + glLoadIdentity(); + + gluPerspective(65, (GLfloat) width + / (GLfloat) height, 1, 1000); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0); + + glMatrixMode(GL_MODELVIEW); + + XMapWindow(disp,win); + + glXSwapBuffers(disp, win); + + makeRasterFont(disp); + +} + +/****************************************************** + * drawLine + ******************************************************/ +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_drawLine(JNIEnv *env, jobject obj, + jint x1, jint y1, + jint x2, jint y2){ + printf("__C__: drawLine\n"); + glBegin(GL_LINES); + + glVertex3d( x1, y1, 0 ); + glVertex3d( x2, y2, 0 ); + + glEnd(); + +} + + +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_drawRect(JNIEnv *env, jobject obj, + jint x, jint y, + jint width, jint height){ + + printf("__C__: drawRect\n"); + glBegin(GL_QUADS); + + glVertex3d( x, y, 0 ); + glVertex3d( x, y+height, 0 ); + glVertex3d( x+width, y+height, 0 ); + glVertex3d( x+width, y, 0 ); + glEnd(); + +} + + +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_drawPoint(JNIEnv *env, jobject obj, + jint x, jint y); + + +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_drawText(JNIEnv *env, jobject obj, + jint x, jint y, + jstring text, jint size){ + int s; + //int l; + const char *str = (const char *)env->GetStringUTFChars( text, 0 ); + + printf("str = %s\n", str); + + s = env->GetStringLength( text); + + // Check the size + printf("s = %d\n", s); + glLoadIdentity(); + + /* + // + // glut stroke fonts + glTranslatef(x,y,0); + glScalef(0.03,0.03,0.03); + + + + for(l = 0; l < s; l++){ + glutStrokeCharacter(GLUT_STROKE_ROMAN , str[l]); + glTranslatef(glutStrokeWidth(GLUT_STROKE_ROMAN,str[l]),0,0); + } + */ + printf("__C__: drawText\n"); + //glColor3f(1,1,1); + + glLoadIdentity(); + + FTFace face; + if( ! face.open("/dos/winnt/Fonts/couri.ttf") ){ + printf("unable to open ttf file"); + return ; + } + + GLTTOutlineFont font(&face); + + int point_size= size; + + if( ! font.create(point_size) ){ + printf("unable to create outline font"); + return ; + } + + glTranslatef(x,y,0); + //glRotatef(45,0,1,0); + //font.setPrecision(4); + font.output( str ); + + // bitmap fonts + //printString(str); + + glLoadIdentity(); + env->ReleaseStringUTFChars( text, 0); +} + + +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_drawingColor(JNIEnv *env, jobject obj, + jdouble r, jdouble g, + jdouble b, jdouble a){ + glColor4d(r,g,b,a); +} + + +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_drawArrow(JNIEnv *env, jobject obj, + jint x, jint y, + jint dx, jint dy, + jint dz){ + glLoadIdentity(); + glScalef(dx,dy,dz); + glBegin(GL_LINES); + + glVertex3f(x,y,0); + glVertex3f(x,y-1,0); + + glVertex3f(x,y,0); + glVertex3f(x+2,y-2,0); + + glVertex3f(x,y,0); + glVertex3f(x+1,y,0); + + glEnd(); + glLoadIdentity(); +} + +/****************************************************** + * swapBuffers + ******************************************************/ +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_swapBuffers(JNIEnv *env, + jobject obj){ + printf("__C__: swapBuffers\n"); + + glXSwapBuffers(disp,win); + + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + glMatrixMode(GL_MODELVIEW); + +} + + +/****************************************************** + * checkEvents + ******************************************************/ +JNIEXPORT void JNICALL +Java_fi_iki_lukka_ZZOpenGLGraphics_checkEvents( JNIEnv *env, jobject obj){ + + XKeyEvent *e_key; + + XButtonEvent *e_but; + + XConfigureEvent *e_conf; + + jclass cls = env->GetObjectClass( obj ); + + jmethodID key_id = env->GetMethodID( cls, + "addKeyEvent", "(II)V"); + + jmethodID button_id = env->GetMethodID( cls, + "addButtonEvent", "(IIII)V"); + + jmethodID conf_id = env->GetMethodID( cls, + "configureEvent", "(II)V"); + + printf("__C__: Check events\n"); + + if ( button_id == 0 || key_id == 0 ) { + printf ("no method id\n"); + return ; + } + + do{ + + int ch; + int type = 0; + + XEvent event; + + XNextEvent(disp, &event); + + switch ( event.type ){ + case ConfigureNotify: + printf("ConfNotify"); + + env->CallVoidMethod( obj, conf_id, + e_conf->width, e_conf->height); + break; + case ButtonPress: + + e_but = (XButtonEvent *) &event; + env->CallVoidMethod( obj, button_id, + e_but->button, e_but->x, e_but->y, 0); + break; + case KeyPress: + + e_key = (XKeyEvent *) &event; + ch = (int )XLookupKeysym(e_key,0); + + env->CallVoidMethod( obj, key_id, ch, type); + break; + default: + + ; + } + + } while( XPending( disp ) ); + + return ; +} diff --git a/Modules/openGL/ZZOpenGLGraphics.java b/Modules/openGL/ZZOpenGLGraphics.java new file mode 100644 index 0000000..29c9d48 --- /dev/null +++ b/Modules/openGL/ZZOpenGLGraphics.java @@ -0,0 +1,606 @@ +/* +ZZGraphics.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ + +package org.gzigzag; +import java.awt.*; +import java.util.*; +import java.awt.event.*; + +/** A class that implements the ZZGraphics interface using OpenGL. + * Tjl's comments: + *

      + *
    • You DON'T want to derive everything from OGLColorThing: that + * slows down rendering. Note how it's done in ZZCanvas: there's + * a ColorThing which sets the foreground/background color which + * is then used. + * + * A state machine... Well, whatever you want. + * Doesn't that somewhat dictate the ordering of drawing, + * what if for some reason (optimization etc.) I want to + * draw the in different order ? I admit it slows rendering, + * but I still would like to have objects with color, not just + * global pens to use in drawing, at least in the object level. + * The implementation of rendering is a completely different thing, + * and shouldn't dictate design issues. + * The actual rendering is unbeliavably simple at the moment, + * but i just wanted to get the java-C-java pipeline to work. /vp + * + * Tjl: In that case, put in a reference to a reusable OGLColorThing + * (in Design Patterns, this is called a flyweight). + * the order of drawing is an excellent point: I was still thinking + * in terms of java.awt.Graphics where order is visible; if we have + * a Z-buffer, that's right. However, if we don't use a Z-buffer, the + * order of rendering is really important. + * + * OTOH: for drawing order, using the color makes sense since in + * some cases changing the color (or material) in OpenGL + * can be one of the slowest operations. + * + * vp: That's why I would like to have attributes of objects to be + * within objects, so i could _easily_ handle them in the order + * that makes most sense at that moment. + * + *
    • For Colors, extend java.awt.Color with alpha - in Java1.2, this + * is already done. + * + * Why ? I just need 4 doubles. Of course there will be methods + * to use Color, but internally i'd like to keep color as + * doubles /vp + * + * Tjl: double = 8 bytes. 4 doubles = 32 bytes. java.awt.Color = 4 bytes. + * first of all, we want to avoid float arithmetic so using bytes or + * an integer would be better. glColor3b can be much faster. + * + * vp: well it's pretty much same to me if it is a byte, float + * or double, but I would like to put it to the format it is used + * at creation time rather than in rendering time. + * + *
    • Why does colorthing have coordinates? + * + * Because a Thing is always in space somewhere. They are objects, + * not just some global "pen swithes". /vp + * + * Tjl: see above for how to handle ColorThing - that way it doesn't + * have coordinates. + * + * One big question is: *DO* we really want actual "models" or just + * drawing things? + * Both the layer above and the layer below are about drawing with a + * pen - why have a layer with models in between? + * + * vp: As long as we already have objects why don't use them. + * It gives much more flexibility when trying to do more complex + * things. BTW, What is the layer above that is about drawing with a + * pen? + * If we would strip the awt from zzcanvas, and added a simple way + * to use any ZZGraphics, then this wouldn't be an issue: you could + * do it the way you wanted in ZZCanvas. And that is the way I think + * it should be done. + * + * + *
    • Basically, check out how ZZCanvas does things and do the same. + * Actually, we might want to think about separating the class + * structure in a way as to have an abstract base class for graphic + * beams and then two implementations, one for opengl and the other + * for awt. Or even have things implement ZZOpenGLThing interface. + * ZZCanvas is pretty abstract. + * + * I don't think so, ZZCanvas is way + * too tightly connected to awt. If one could bring his own graphics, + * with some basic methods, drawCell, drawLink etc., then it would + * be good. In fact that is the way I think it should be done. /vp + * + * Tjl: Explain further. The connection to awt is actually limited to + * the methods render*. + * + * vp: Exactly. We should have ZZCanvas(zzgraphics g), so we could use + * zzcanvas with any graphics we would like to implement. All rendering + * would go through that zzgraphics. So every render method + * should have something like g.drawLine, where g is zzgraphics not + * graphics. + * + *
    • if you extend Component, do you need addKeyListener and + * addMouseListener? + * + * If I want to throw my own keyevents, yes./vp + * + * they are already implemented there. + * + * Is there somewhere a method to fire your own key & mouse events? /vp + * + * Alternatively, not deriving from Component might be good. + * + * I know, I should have added a Component and used that to fire + * those events... /vp + * + * java.awt.Component.processEvent(KeyEvent) /vp + * + *
    + */ + +public class ZZOpenGLGraphics extends Component implements ZZGraphics, Runnable { + String rcsid = "$Id: ZZOpenGLGraphics.java,v 1.9 2000/11/05 12:49:39 tjl Exp $"; + + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + KeyListener actionListener = null; + + public void addKeyListener(KeyListener l) { + actionListener = AWTEventMulticaster.add(actionListener, l); + } + public void removeKeyListener(KeyListener l) { + actionListener = AWTEventMulticaster.remove(actionListener, l); + } + public void processKeyEvent(KeyEvent e) { + + if (actionListener != null) { + actionListener.keyPressed(e); + } + } + + MouseListener mouseListener = null; + + public void addMouseListener(MouseListener l) { + mouseListener = AWTEventMulticaster.add(mouseListener, l); + } + + public void removeMouseListener(MouseListener l) { + mouseListener = AWTEventMulticaster.remove(mouseListener, l); + } + + + public void processMouseEvent(MouseEvent e) { + + if (mouseListener != null){ + mouseListener.mouseClicked(e); + } + } + + int GLcontext = 0; + int window = 0; + int display = 0; + + int font_Size = 10; + + /* just testing */ + int cx = 0; + int cy = 0; + int cz = 50; + + + + Vector things = new Vector(); + + + public abstract class OGLThing { + + int x; + int y; + + OGLThing(int x, int y ){ + this.x = x; + this.y = y; + } + + OGLThing( ){ + x = 0; + y = 0; + } + + public void coords(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { return x; } + + public int getYs() { return y; } + + // rendes to this context + public abstract void render(); + + } + + public class OGLColorThing extends OGLThing{ + + float r; + float g; + float b; + float a; + + OGLColorThing(int x, int y, float r, float g, float b, float a){ + super(x,y); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + OGLColorThing(){ + super(); + this.r = 1; + this.g = 1; + this.b = 1; + this.a = 1; + + } + + OGLColorThing(int x, int y){ + super(x,y); + this.r = 1; + this.g = 1; + this.b = 1; + this.a = 1; + + } + + OGLColorThing(Color c){ + super(0,0); + setColor(c); + + } + + public void setColor(Color c){ + + } + + public void setColor(int r, int g, int b, int a){ + this.r = r; + this.g = g; + this.b = b; + this.a = a; + + } + + public void render(){ + p("COLOR: RENDER\n"); + /* this is just a temporary solution, + add checking of color */ + drawingColor(r,g,b,a); + } + } + + public abstract class OGLCell extends OGLColorThing{ + + ZZCell c; + + public OGLCell(){ + super(); + c = null; + } + + public OGLCell(int x, int y, ZZCell c){ + super(x,y); + this.c = c; + } + public OGLCell( ZZCell c ){ + super(); + this.c = c; + } + + } + + public class OGL2DCell extends OGLCell { + + int width; + int height; + + + + public OGL2DCell(){ + super(); + width = 0; + height = 0; + } + + public OGL2DCell(int x, int y, int width, int height, ZZCell cell){ + super(x,y,cell); + this.width = width; + this.height = height; + + } + + public void render(){ + + super.render(); + + p("CELL: RENDER" + x + " " +y); + + drawRect(x,y,width,height); + + if( c != null ) { + drawingColor(0,0,0,1); + + drawText(x+2, y+2, c.getText(),10); + } + } + } + + public class OGLText extends OGLColorThing{ + int size; + String text; + + public OGLText(int x, int y, String txt){ + super(x,y); + text = txt; + size = 10; + } + + public void render(){ + //super.render(); + drawText(x, y, text, size ); + } + } + + public class OGLLink extends OGLColorThing{ + + int x2; + int y2; + + OGLLink(int x1, int y1, int x2, int y2){ + super(x1,y1); + this.x2 = x2; + this.y2 = y2; + } + + public void render(){ + super.render(); + drawLine(super.x,super.y, x2, y2); + } + + } + + public class OGLLine extends OGLColorThing{ + int x2; + int y2; + + OGLLine(int x1, int y1, int x2, int y2){ + super(x1,y1); + this.x2 = x2; + this.y2 = y2; + } + + public void render(){ + super.render(); + drawLine(super.x,super.y, x2, y2); + } + + } + + public class OGLMark extends OGLColorThing{ + + ZZCell c; + + int h; + + OGLMark(int x1, int y1, int h, ZZCell c){ + super(x1,y1); + this.c = c; + this.h = h; + } + + public void render(){ + super.render(); + drawLine(super.x,super.y, x, y+h); + } + + } + + + class OGLArrow extends OGLColorThing{ + // Hmm... + int dir_x; + int dir_y; + int dir_z; + + public OGLArrow(int x, int y){ + super(x,y); + dir_x = 2; + dir_y = 2; + dir_z = 1; + } + + public void render(){ + super.render(); + drawArrow(super.x,super.y, dir_x, dir_y, dir_z); + } + } + + public Dimension getSize(){ + return null; + } + + public Dimension getDefaultCellSize(ZZCell c){ + return null; + } + + public void putCell(ZZCell c, int x, int y, int w, int h, String style){ + things.addElement(new OGL2DCell(x,y,w,h,c)); + } + + public void putLinks(String dim, float dx, float dy){ + + } + +// public void putBeams(ZZCanvasTextSpanSet set1, ZZCanvasTextSpanSet set2){ +// +// } + + public void setColor(Color c){} + + public int getDefaultFontSize(){ return 0;} + + public FontMetrics getFontMetrics(Font f){ return null;} + + public void setFont(Font f){} + + public void putPolyLine(int x1, int y1, int x2, int y2, String style){} + + public void putText(String s, int x, int y){ + things.addElement(new OGLText(x,y,s)); + } + + public void putText(String s, int x, int y, int size){ + things.addElement(new OGLText(x,y,s)); + } + /* + public void putText(String s, int x, int y, int z){ + things.addElement(new OGLText(x,y,z,s)); + } + */ + + public Object putSpan(Span s, String str, ZZCell c, int x, int y, + int w, int h, int xoffs, int yoffs, + ZZCanvasTextSpanSet collect, + Object prev, + Font f, FontMetrics fm){ + return null;} + + public void putTextMark(int x, int y, int h, ZZCell mkc){ + things.addElement(new OGLMark(x,y,h, mkc)); + } + + public void putLine(int x1, int y1, int x2, int y2, String style){ + //drawLine(x1, y1, x2, y2); + things.addElement(new OGLLine(x1,y1,x2,y2)); + + } + + public void putCoordNames(String[] names){} + + public void putArrow( int x1, int y1, + int x2, int y2, + Color intern, String style){ + things.addElement(new OGLArrow(x1,y1)); + } + +// public void putDragCursor(ZZGraphics.DragCursor dc, int x, int y){} + + // public class OpenGLDragCursor implements ZZGraphics.DragCursor { +// public boolean accept(Object o){ return false; } + // } + + static { + System.loadLibrary("zz3d"); + } + + public void render(){ + p("RENDER:"); + + for (Enumeration e = things.elements() ; e.hasMoreElements() ;) { + ((OGLThing)e.nextElement()).render(); + } + + swapBuffers(); + + } + + private Thread thread = null; + + public void start() { + if (thread == null) { + thread = new Thread(this, "render"); + thread.start(); + } + } + + + public void run() { + + Thread myThread = Thread.currentThread(); + p("RUN:"); + + while (thread == myThread) { + checkEvents(); + render(); + try { + Thread.sleep(100); + } catch (InterruptedException e){ + // the VM doesn't want us to sleep anymore, + // so get back to work + } + } + } + + void addKeyEvent(int key, int type){ + p("KEY_EVENT: " + (char)key + " " + type); + // XXX add missing info: time, modifiers ... + processKeyEvent(new KeyEvent(this,1000,1,0,key,(char)key)); + } + + void addButtonEvent(int button, int x, int y, int modifiers){ + p("BUTTON_EVENT: " + button + " " + x + y); + processMouseEvent(new MouseEvent(this,1001,1,0,x,y,1,false)); + } + + void configureEvent(int x, int y){ + p("CONFIGURE_EVENT:" + x + " " + y); + } + + /******************/ + /* NATIVE METHODS */ + /******************/ + + /** + * This is supposed to create a native window, put right values + * to variales in this class, create glx context... + * + */ + public native void openWindow( int width, int height ); + + public native void drawLine( int x1, int y1, int x2, int y2 ); + + public native void draw3DLine( int x1, int y1, int z1, + int x2, int y2, int z2 ); + + public native void drawRect( int x, int y, int width, int height ); + + public native void draw2DPoint( int x, int y ); + + public native void draw3DPoint( int x, int y, int z ); + + public native void drawText( int x, int y, String text, int size ); + + public native void draw3DText( int x, int y, int z, + String text, int size ); + + public native void drawingColor( double r, double g, double b, double a ); + + public native void drawArrow(int x, int y, + int dir_x, int dir_y, int dir_z); + + public native void draw3DArrow(int x, int y, int z, + int dir_x, int dir_y, int dir_z); + + public native void swapBuffers(); + + public native void checkEvents(); + + public native void setCamera( int x, int y, int z, + int ex, int ey, int ez, + int lx, int ly, int lz ); +} + diff --git a/Modules/openGL/fi_iki_lukka_ZZOpenGLGraphics.h b/Modules/openGL/fi_iki_lukka_ZZOpenGLGraphics.h new file mode 100644 index 0000000..c733d44 --- /dev/null +++ b/Modules/openGL/fi_iki_lukka_ZZOpenGLGraphics.h @@ -0,0 +1,125 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class fi_iki_lukka_ZZOpenGLGraphics */ + +#ifndef _Included_fi_iki_lukka_ZZOpenGLGraphics +#define _Included_fi_iki_lukka_ZZOpenGLGraphics +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: openWindow + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_openWindow + (JNIEnv *, jobject, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: drawLine + * Signature: (IIII)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_drawLine + (JNIEnv *, jobject, jint, jint, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: draw3DLine + * Signature: (IIIIII)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_draw3DLine + (JNIEnv *, jobject, jint, jint, jint, jint, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: drawRect + * Signature: (IIII)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_drawRect + (JNIEnv *, jobject, jint, jint, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: draw2DPoint + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_draw2DPoint + (JNIEnv *, jobject, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: draw3DPoint + * Signature: (III)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_draw3DPoint + (JNIEnv *, jobject, jint, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: drawText + * Signature: (IILjava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_drawText + (JNIEnv *, jobject, jint, jint, jstring, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: draw3DText + * Signature: (IIILjava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_draw3DText + (JNIEnv *, jobject, jint, jint, jint, jstring, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: drawingColor + * Signature: (DDDD)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_drawingColor + (JNIEnv *, jobject, jdouble, jdouble, jdouble, jdouble); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: drawArrow + * Signature: (IIIII)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_drawArrow + (JNIEnv *, jobject, jint, jint, jint, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: draw3DArrow + * Signature: (IIIIII)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_draw3DArrow + (JNIEnv *, jobject, jint, jint, jint, jint, jint, jint); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: swapBuffers + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_swapBuffers + (JNIEnv *, jobject); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: checkEvents + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_checkEvents + (JNIEnv *, jobject); + +/* + * Class: fi_iki_lukka_ZZOpenGLGraphics + * Method: setCamera + * Signature: (IIIIIIIII)V + */ +JNIEXPORT void JNICALL Java_fi_iki_lukka_ZZOpenGLGraphics_setCamera + (JNIEnv *, jobject, jint, jint, jint, jint, jint, jint, jint, jint, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Modules/panes/PaneView.zob b/Modules/panes/PaneView.zob new file mode 100644 index 0000000..acac4ed --- /dev/null +++ b/Modules/panes/PaneView.zob @@ -0,0 +1,76 @@ +/* +PaneView.zob + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A view that shows different other views on different panes. + * Like the SplitNileView, but more generally useful. Currently, exactly two + * panes are shown. + */ + +public class PaneView implements FlobView, ZOb { +public static final String rcsid = "$Id: PaneView.zob,v 1.1 2001/01/20 08:52:40 bfallenstein Exp $"; + + public static final boolean dbg = true; + private static final void p(String s) { if(dbg) System.out.println(s); } + private static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + /** The space to leave between the two panes. */ + int space + = 20; + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell win, String[] dims, ZZCell accursed) { + ZZCell lpane = win.s("d.panes", 1); + ZZCell rpane = win.s("d.panes", 2); + if(rpane == null) + throw new ZZError("No panes found for PaneView"); + + ZZCell leftacc = ZZCursorReal.get(lpane); + ZZCell rightacc = ZZCursorReal.get(rpane); + + ZZCell lapp = lpane.h("d.pane-app"); + ZZCell rapp = rpane.h("d.pane-app"); + ZZCell linkapp = win.h("d.pane-link-app"); + + Dimension size = new Dimension(into.getSize()); + size.width = (size.width - space) / 2; + FlobSet left = into.create(size), right = into.create(size); + + FlobView view = ApplitudeMgr.getView(lapp); + view.raster(left, fact, lpane, dims, leftacc); + + view = ApplitudeMgr.getView(rapp); + view.raster(right, fact, rpane, dims, rightacc); + + into.fetch(left, 0, 0, 0); + into.fetch(right, size.width + space, 0, 0); + + view = ApplitudeMgr.getView(linkapp); + view.raster(into, fact, win, dims, accursed); + } + +} \ No newline at end of file diff --git a/Modules/prez/Prez.java b/Modules/prez/Prez.java new file mode 100644 index 0000000..658033d --- /dev/null +++ b/Modules/prez/Prez.java @@ -0,0 +1,51 @@ +/* +Prez.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** A simple presentation module. + */ + +public class Prez { +public static final String rcsid = "$Id: Prez.java,v 1.4 2000/09/19 10:32:03 ajk Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + } + public ZOb newZOb(String id) { + if(id.equals("R")) + return new PrezRaster(); + + return null; + } + }; +} diff --git a/Modules/prez/PrezRaster.zob b/Modules/prez/PrezRaster.zob new file mode 100644 index 0000000..5eda7f2 --- /dev/null +++ b/Modules/prez/PrezRaster.zob @@ -0,0 +1,173 @@ +/* +Prez.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka and Asko Soukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; +import java.io.*; + +/** A simple presentation raster. + * The structure is described along three dimensions: + * hierarchy, sibling and cross-reference (x, y and z). + * On these, the hierarchy is arranged as a corner list with an empty + * corner cell, and the cross-references are simply siblings + * connected. + */ + +public class PrezRaster implements FlobView, ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + STRUCTPARAMS { + /** The vstream raster used for the header. */ + ZOb hdrvs // VStreamRaster + = new RankTextView() {{ + width = 650; + dim = "d.foo"; + }}; + /** The vstream raster used for the items. */ + ZOb txtvs // RankTextView + = new RankTextView() {{ + width = 500; + dim = "d.foo"; + }}; + /** The vstream raster used for the crossrefs. */ + ZOb xrefvs // RankTextView + = new RankTextView() {{ + width = 500; + dim = "d.foo"; + }}; + + /** The amount to shift the header. */ + int hdrindent + = 30; + + /** The amount to shift the items. */ + int indent + = 50; + + /** The amount to space the items. */ + int space + = 30; + + int topmargin + = 120; + + int afterhdr + = 0; + + ScalableFont hdrfont + = new ScalableFont("SansSerif", Font.PLAIN, 32); + + ScalableFont txtfont + = new ScalableFont("SansSerif", Font.PLAIN, 24); + + ScalableFont xreffont + = new ScalableFont("SansSerif", Font.PLAIN, 10); + + int hdrwidth + = 650; + int txtwidth + = 500; + } + + String next = "d.2"; + String hier = "d.1"; + String cross = "d.3"; + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + + hier = dims[0]; + next = dims[1]; + cross = dims[2]; + + ZZCell hdr = null; + + /* Something to work with circular ranks. + * Goes rank backwards and gets the first available cell + * on the negative direction on the hier-dimension. + * Otherwise gets the accursed cell. */ + hdr = accursed.s(hier, -1); + int i = -1; + while (hdr == null) { + if (accursed.s(next, i) == null) break; + hdr = accursed.s(next, i).s(hier, -1); + if (i < -20) break; + i--; + } + + if (hdr == null) hdr = accursed; + + RankTextView hdrvs = (RankTextView)this.hdrvs; + RankTextView txtvs = (RankTextView)this.txtvs; + RankTextView xrefvs = (RankTextView)this.xrefvs; + + hdrvs.font = hdrfont; + txtvs.font = txtfont; + xrefvs.font = xreffont; + + hdrvs.width = hdrwidth; + txtvs.width = txtwidth; + + hdrvs.readParams(null); + txtvs.readParams(null); + xrefvs.readParams(null); + + int y = topmargin; + Rectangle bds = hdrvs.raster(into, hdr, 0, false, + hdrindent, y); + p("Raster 1: "+bds); + + y += bds.height + afterhdr; + + ZZCell cur = hdr.s(hier, 1); + if(cur == null) return; + + LoopDetector l = new LoopDetector(); + while(true) { + cur = cur.s(next, 1); + if(cur == null) break; + if(cur == hdr.s(hier, 1)) break; + l.detect(cur); + bds = txtvs.raster(into, cur, 0, false, indent, y); + p("Raster n: "+bds); + // indicate that there is more + if(cur.s(hier, 1) != null) { + into.add(new LineDecor(bds.x+bds.width, bds.y, + bds.x+bds.width, bds.y+bds.height, + Color.blue, 1)); + } + if(cur.s(cross, -1) != null) + xrefvs.raster(into, cur.s(cross,-1), + 0, false, 400, bds.y-15); + if(cur.s(cross, 1) != null) + xrefvs.raster(into, cur.s(cross,1), + 0, false, 400, bds.y+bds.height+5); + + y += bds.height + space; + } + } +} +// vim: set syntax=java : diff --git a/Modules/servlet/VCServlet.java b/Modules/servlet/VCServlet.java new file mode 100644 index 0000000..8b4b5a0 --- /dev/null +++ b/Modules/servlet/VCServlet.java @@ -0,0 +1,144 @@ +/* +VCServlet.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.*; + + +/** A Virtual Community demo servlet. + */ + +public class VCServlet extends ZZServlet { +public static final String rcsid = "$Id: VCServlet.java,v 1.2 2001/02/28 03:02:56 tjl Exp $"; + + String getURL(ZZCell c) { + return "org.gzigzag.module.VCServlet?"+c.getID(); + } + + void printAuthor(ZZCell txt, PrintWriter wr) { + ZZCell h = txt.h("d.author", true); + if(h != null) { + wr.print(""+h.getText()+""); + } + } + + void printmsg(ZZCell h, PrintWriter wr) { + printAuthor(h, wr); + wr.print(": "); + wr.print(""+ h.getText() + ""); + } + + void printRefs(ZZCell thing, PrintWriter wr) { + wr.print("

    Referenced in:

      "); + while((thing = thing.s("d.kahva")) != null) { + ZZCell h = thing.h("d.text"); + wr.print("
    • "); + printmsg(h, wr); + } + wr.print("
    \n"); + } + + void printAuthored(ZZCell thing, PrintWriter wr) { + wr.print("

    Messages written:

      "); + while((thing = thing.s("d.author")) != null) { + ZZCell h = thing.h("d.text"); + wr.print("
    • "); + wr.print(""+ h.getText() + ""); + } + wr.print("
    \n"); + } + + void printReplies(ZZCell thing, PrintWriter wr) { + thing = thing.s("d.replies"); + if(thing == null) return; + + wr.print("

    Replies:

      "); + while((thing = thing.s("d.replies-list")) != null) { + ZZCell h = thing.h("d.text"); + wr.print("
    • "); + printmsg(h, wr); + } + wr.print("
    \n"); + } + + + void printText(ZZCell start, PrintWriter wr) { + wr.print("

    "+start.getText()+"

    "); + ZZCell im = start.h("d.images", true); + if(im != null) { + wr.print(""); + } + printAuthor(start, wr); + wr.print("

    "); + ZZCell orig = start; + while((start = start.s("d.text")) != null) { + ZZCell h = start.h("d.kahva", true); + String txt = start.getText(); + if(h != null) { + txt = ""+ txt + ""; + } + wr.print(txt); + } + if(orig.s("d.author", -1) == null) + printAuthored(orig, wr); + ZZCell inreply = orig.h("d.replies-list").s("d.replies",-1); + if(inreply != null) { + wr.print("

    In reply to "); + printmsg(inreply, wr); + } + printReplies(orig, wr); + + printRefs(orig, wr); + } + + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException { + try { + synchronized(space) { + // resp.getWriter().print("HELLO\n\n!!\n\n"); + String s = req.getQueryString(); + PrintWriter wr = resp.getWriter(); + wr.print("HELLO\n\n!!\n\n Query: '"+s+"'\n"); + ZZCell c; + if(s == null || s.equals("")) + c = space.getHomeCell().s("d.1"); + else + c = space.getCellByID(s); + wr.print("
    Cell content: '"+c.getText()+"'\n"); + + printText(c, wr); + + wr.close(); + } + } catch(Exception e) { + throw new ServletException("doGet: ", e); + } + } + +} + + diff --git a/Modules/servlet/ZZServlet.java b/Modules/servlet/ZZServlet.java new file mode 100644 index 0000000..def768e --- /dev/null +++ b/Modules/servlet/ZZServlet.java @@ -0,0 +1,78 @@ +/* +ZZServlet.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.*; + + +/** A base class for servlets based on ZZ spaces. + */ + +public class ZZServlet extends HttpServlet { +public static final String rcsid = "$Id: ZZServlet.java,v 1.1 2001/01/17 14:27:20 tjl Exp $"; + + static Hashtable spaces = new Hashtable(); + static Object lock = new Object(); + + static ZZSpace getSpace(String name) { + synchronized(lock) { + ZZSpace s = (ZZSpace)spaces.get(name); + if(s == null) { + File f = new File(name); + s = new ZZCacheDimSpace(new DirStreamSet(f)); + spaces.put(name, s); + } + return s; + } + } + + + ZZSpace space; + + public void init(ServletConfig config) throws ServletException { + synchronized(lock) { + String s = config.getInitParameter("space"); + if(s == null) { + // throw new ServletException("No space specified!"); + s = "/tmp/testspace"; + } + space = getSpace(s); + } + } + + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException { + try { + synchronized(space) { + resp.getWriter().print("HELLO\n\n!!\n\n"); + } + } catch(Exception e) { + throw new ServletException("doGet: ", e); + } + } + +} + diff --git a/Modules/servlet/startjetty b/Modules/servlet/startjetty new file mode 100644 index 0000000..d99a6d6 --- /dev/null +++ b/Modules/servlet/startjetty @@ -0,0 +1,4 @@ +#!/bin/sh + +# java com.mortbay.HTTP.Configure.ServletServer 8080 . . +java com.mortbay.Jetty.Server ../Modules/servlet/zzserv2.prp diff --git a/Modules/servlet/zzserv.prp b/Modules/servlet/zzserv.prp new file mode 100644 index 0000000..11b00e7 --- /dev/null +++ b/Modules/servlet/zzserv.prp @@ -0,0 +1,42 @@ +*.CLASS : com.mortbay.HTTP.HttpServer +*.LISTENER.*.CLASS : com.mortbay.HTTP.HttpListener +*.*.Log.CLASS : com.mortbay.HTTP.Handler.LogHandler +*.*.Auth.CLASS : com.mortbay.HTTP.Handler.BasicAuthHandler +*.*.Alias.CLASS : com.mortbay.HTTP.Handler.TranslateHandler +*.*.Filter.CLASS : com.mortbay.HTTP.Handler.FilterHandler +*.*.Html.CLASS : com.mortbay.HTTP.Filter.HtmlFilter +*.*.Param.CLASS : com.mortbay.HTTP.Handler.ParamHandler +*.*.Session.CLASS : com.mortbay.HTTP.Handler.SessionHandler +*.*.Servlet.CLASS : com.mortbay.HTTP.Handler.ServletHandler +*.*.File.CLASS : com.mortbay.HTTP.Handler.FileHandler +*.*.Forward.CLASS : com.mortbay.HTTP.Handler.ForwardHandler +*.*.NotFound.CLASS : com.mortbay.HTTP.Handler.NotFoundHandler +*.*.Proxy.CLASS : com.mortbay.HTTP.Handler.ProxyHandler +*.*.DefaultEx.CLASS : com.mortbay.HTTP.Handler.DefaultExceptionHandler +*.*.TerseEx.CLASS : com.mortbay.HTTP.Handler.TerseExceptionHandler + +*.*.ZZServer.CLASS : org.gzigzag.module.ZZServlet +*.*.Servlet.PROPERTY.SERVLET.ZZServer.CLASS : org.gzigzag.module.ZZServlet +*.*.Servlet.PROPERTY.SERVLET.ZZServer.PROPERTY.space : /home/tjl/tspc +*.*.Servlet.PROPERTY.CLASSPATH : /home/tjl/gzigzag/Java/org/gzigzag:/home/tjl/gzigzag/Java/org/gzigzag/module:/home/tjl/gzigzag/Java/ + +SERVERS : main +main.root.PATHS : / + +main.LISTENER.all.ADDRS : 0.0.0.0:8080;127.0.0.1:8888 +main.LISTENERS : all +main.STACKS : root + + + +main.root.HANDLERS : Servlet;NotFound + +*.*.Servlet.PROPERTY.PATHS : / + +*.*.Servlet.PROPERTY.Loader : com.mortbay.HTTP.Handler.FileJarServletLoader +*.*.Servlet.PROPERTY.AutoReloadDynamicServlets : True +*.*.Servlet.PROPERTY.SERVLET.*.Initialize : False +*.*.Servlet.PROPERTY.SERVLET.Dump.Initialize : True +*.*.Filter.PROPERTY.Html.CLASS : com.mortbay.HTTP.Filter.HtmlFilter + + diff --git a/Modules/servlet/zzserv2.prp b/Modules/servlet/zzserv2.prp new file mode 100644 index 0000000..a22d05d --- /dev/null +++ b/Modules/servlet/zzserv2.prp @@ -0,0 +1,205 @@ +# ======================================================================== +# Abbreviated Configuration file for com.mortbay.Jetty.Demo +# +# The format of this file is parsed by the com.mortbay.Util.PropertyTree +# class and interpreted by the com.mortbay.Jetty.Server class to +# construct, configure and start 1 or more HttpServer instances. +# +# This configuration file is abbrevited using the features of +# com.mortbay.Util.PropertyTree. It can be run with the command +# java com.mortbay.Jetty.Server etc/JettyMinimalDemo.prp +# +# A none abbreviated version of this configuration can be seen in +# JettyDemo.prp and associated files +# ------------------------------------------------------------------------ + +# ======================================================================== +# Default CLASS definitions +# ------------------------------------------------------------------------ +*.CLASS : com.mortbay.HTTP.HttpServer +*.LISTENER.*.CLASS : com.mortbay.HTTP.HttpListener +*.*.Log.CLASS : com.mortbay.HTTP.Handler.LogHandler +*.*.Auth.CLASS : com.mortbay.HTTP.Handler.BasicAuthHandler +*.*.Alias.CLASS : com.mortbay.HTTP.Handler.TranslateHandler +*.*.Filter.CLASS : com.mortbay.HTTP.Handler.FilterHandler +*.*.Html.CLASS : com.mortbay.HTTP.Filter.HtmlFilter +*.*.Param.CLASS : com.mortbay.HTTP.Handler.ParamHandler +*.*.Session.CLASS : com.mortbay.HTTP.Handler.SessionHandler +*.*.Servlet.CLASS : com.mortbay.HTTP.Handler.ServletHandler +*.*.File.CLASS : com.mortbay.HTTP.Handler.FileHandler +*.*.Forward.CLASS : com.mortbay.HTTP.Handler.ForwardHandler +*.*.NotFound.CLASS : com.mortbay.HTTP.Handler.NotFoundHandler +*.*.Proxy.CLASS : com.mortbay.HTTP.Handler.ProxyHandler +*.*.DefaultEx.CLASS : com.mortbay.HTTP.Handler.DefaultExceptionHandler +*.*.TerseEx.CLASS : com.mortbay.HTTP.Handler.TerseExceptionHandler + +# ======================================================================== +# Default Servlet CLASS definitions +# ------------------------------------------------------------------------ +*.*.Servlet.PROPERTY.SERVLET.Dump.CLASS : com.mortbay.Servlets.Dump +*.*.Servlet.PROPERTY.SERVLET.Exit.CLASS : com.mortbay.Servlets.Exit +*.*.Servlet.PROPERTY.SERVLET.Session.CLASS : com.mortbay.Servlets.SessionDump +*.*.Servlet.PROPERTY.SERVLET.PropertyTree.CLASS: com.mortbay.Servlets.PropertyTreeEditor +*.*.Servlet.PROPERTY.SERVLET.Config.CLASS : com.mortbay.Servlets.ConfigDump +*.*.Servlet.PROPERTY.SERVLET.Debug.CLASS : com.mortbay.Servlets.DebugServlet +*.*.Servlet.PROPERTY.SERVLET.Laf.CLASS : com.mortbay.Servlets.LookAndFeelServlet +# ======================================================================== +# Default ServletHandler Properties +# ------------------------------------------------------------------------ +*.*.Servlet.PROPERTY.PATHS : /servlet/;/SERVLET/;/Servlet/ +*.*.Servlet.PROPERTY.CLASSPATH : ./servlets +*.*.Servlet.PROPERTY.Loader : com.mortbay.HTTP.Handler.FileJarServletLoader +*.*.Servlet.PROPERTY.AutoReloadDynamicServlets : True +*.*.Servlet.PROPERTY.SERVLET.*.Initialize : False +*.*.Servlet.PROPERTY.SERVLET.Dump.Initialize : True +*.*.Filter.PROPERTY.Html.CLASS : com.mortbay.HTTP.Filter.HtmlFilter + +# ======================================================================== +# Default FileHandler Properties +# ------------------------------------------------------------------------ +*.*.File.PROPERTY.AllowPut : False +*.*.File.PROPERTY.AllowDelete : False +*.*.File.PROPERTY.AllowDir : True +*.*.File.PROPERTY.Indexes : index.html;index.htm +*.*.File.PROPERTY.MaxCachedFiles : 100 +*.*.File.PROPERTY.MaxCachedFileSize : 8192 + + +# ======================================================================== +# Define the server instances to be configured by this file: +# SERVERS - list if defined server names +# PROPERTY.* - Definition of global properties +# PROPERTIES - File of globl properties +# servername.* - PropertyTree describing server "servername". +# +# Defined global properties are: +# DefaultPageType - The class name of the default com.mortbay.HTML.Page +# type. +# ------------------------------------------------------------------------ +SERVERS : main;proxy +PROPERTY.DefaultPageType : com.mortbay.Jetty.JettyLaF + +# ======================================================================== +# Define the server instance named "main" +# CLASS - The class name of the server. Must either be +# com.mortbay.HTTP.HttpServer or a decendant. +# LISTENER.name.CLASS - HttpListener classname or decendant +# LISTENER.name.ADDRS - List of addresses and ports to listen on +# STACKS - List of handler stack names. +# EXCEPTIONS - List of exception handler stack names. +# PROPERTY.* - Properties for this server +# PROPERTIES - File of properties for this server. +# +# Defined server properties are: +# SessionMaxInactiveInterval - Max idle time Ms before session death +# MinListenerThreads - Min listener threads per listener +# MaxListenerThreads - Max listener threads per listener +# MaxListenerThreadIdleMs - Max idle time Ms before listen thread +# death +# MimeMap - Property file of MIME mappings +# +# ------------------------------------------------------------------------ +main.LISTENERS : all +main.LISTENER.all.ADDRS : 0.0.0.0:8080;127.0.0.1:8888 +main.STACKS : root;files +main.EXCEPTIONS : defaultEx +main.PROPERTY.SessionMaxInactiveInterval : 3600 +main.PROPERTY.MinListenerThreads : 3 +main.PROPERTY.MaxListenerThreads : 20 +main.PROPERTY.MaxListenerThreadIdleMs : 60000 +# XXX +# main.PROPERTY.MimeMap : ./etc/Mime.prp + +# ======================================================================== +# Define the handler instances handler stack "root" in server "main" +# PATHS - List of PathMap path specifiactions for this stack +# HANDLERS - List of handler names for this stack. +# EXCEPTIONS - List of exception handler names for this stack. +# name.CLASS - The classname for the handler "name" +# name.PROPERTY.* - Properties defined for handler "name" +# name.PROPERTIES - file of properties defined for handler "name" +# ------------------------------------------------------------------------ +main.root.PATHS : / +main.root.HANDLERS : Log;Auth;Alias;Filter;Param;Session;Servlet;File;Forward;NotFound +main.root.Log.PROPERTY.File : ./log/demo.log +main.root.Log.PROPERTY.Append : False +main.root.Log.PROPERTY.LongForm : True +main.root.Log.PROPERTY.CountContentLength : False +main.root.Log.PROPERTY.DateFormat : dd/MMM/yyyy:HH:mm:ss +# main.root.Auth.PROPERTIES : ./etc/JettyDemoRealms.prp +# main.root.Alias.PROPERTIES : ./etc/JettyDemoAlias.prp +main.root.Filter.PROPERTY.Html.PATHS : / +main.root.Param.PROPERTY.CookiesAsParameters : False +# ------------------------------------------------------------------------ +main.root.Servlet.PROPERTY.SERVLET.Dump.PATHS : /Dump%;*.DUMP +main.root.Servlet.PROPERTY.SERVLET.Dump.CHUNK : True +main.root.Servlet.PROPERTY.SERVLET.Dump.PROPERTY.AttrX : ValueX +main.root.Servlet.PROPERTY.SERVLET.Dump.PROPERTY.AttrY : ValueY +main.root.Servlet.PROPERTY.SERVLET.Dump.PROPERTY.AttrZ : ValueZ +# main.root.Servlet.PROPERTY.SERVLET.Dump.PROPERTIES : ./etc/JettyDemoDump.prp +main.root.Servlet.PROPERTY.SERVLET.Exit.PATHS : /Exit +main.root.Servlet.PROPERTY.SERVLET.Session.PATHS : /SessionDump +main.root.Servlet.PROPERTY.SERVLET.PropertyTree.PATHS : /PropertyTree +main.root.Servlet.PROPERTY.SERVLET.Config.PATHS : /Config$ +main.root.Servlet.PROPERTY.SERVLET.Debug.PATHS : /Debug$ +main.root.Servlet.PROPERTY.SERVLET.Multi.PATHS : /Demo/push +main.root.Servlet.PROPERTY.SERVLET.Multi.CLASS : com.mortbay.Jetty.MultiPartCount +main.root.Servlet.PROPERTY.SERVLET.Gen.PATHS : /Demo/generate +main.root.Servlet.PROPERTY.SERVLET.Gen.CLASS : com.mortbay.Jetty.GenerateServlet +main.root.Servlet.PROPERTY.SERVLET.GenL.PATHS : /Demo/generateLaf +main.root.Servlet.PROPERTY.SERVLET.GenL.CLASS : com.mortbay.Jetty.GenerateLafServlet +main.root.Servlet.PROPERTY.SERVLET.Upload.PATHS : /Upload$ +main.root.Servlet.PROPERTY.SERVLET.Upload.CLASS : com.mortbay.Jetty.UploadServlet +main.root.Servlet.PROPERTY.SERVLET.Laf.PATHS : /Jetty/Demo/;/Jetty/Info/;/Jetty/Config/;/Jetty/Program/ +main.root.Servlet.PROPERTY.SERVLET.Laf.PROPERTY.ResourceBase: /laf +main.root.Servlet.PROPERTY.SERVLET.Index.PATHS : /Jetty|;/Jetty/Info|;/Jetty/Demo|;/Jetty/Program|;/Jetty/Config| +main.root.Servlet.PROPERTY.SERVLET.Index.CLASS : com.mortbay.Jetty.DemoIndex +# ------------------------------------------------------------------------ +main.root.File.PROPERTY.FILES.FileBase.PATHS : /;/FileBase% +main.root.File.PROPERTY.FILES.FileBase.DIRECTORY : ./FileBase +# ------------------------------------------------------------------------ +main.root.Forward.PROPERTY.FORWARD.demo.PATHS : /Forward% +main.root.Forward.PROPERTY.FORWARD.demo.URL : http://localhost:8080 +main.root.Forward.PROPERTY.FORWARD.proxy.PATHS : http +main.root.Forward.PROPERTY.FORWARD.proxy.URL : http://localhost:8081 + + +# ======================================================================== +# Exception handler stacks 'default' and 'terse' for server 'main' +# HANDLERS - List of exception handler names for each stack. +# PATHS - List of PathMap path specifiactions for each stack +# name.CLASS - The classname for the handler "name" +# ------------------------------------------------------------------------ +main.defaultEx.PATHS : / +main.defaultEx.HANDLERS : DefaultEx +main.defaultEx.DefaultEx.CLASS : com.mortbay.HTTP.Handler.DefaultExceptionHandler + + +# ======================================================================== +# Define the handler stack "files" in server "main" +# ------------------------------------------------------------------------ +main.files.HOSTS : +main.files.PATHS : /javadoc%;/laf% +main.files.HANDLERS : File;NotFound +main.files.File.PROPERTY.FILES.Laf.PATHS : /laf +main.files.File.PROPERTY.FILES.Laf.DIRECTORY : ./FileBase +main.files.File.PROPERTY.FILES.Javadoc.PATHS : /javadoc +main.files.File.PROPERTY.FILES.Javadoc.DIRECTORY : ./javadoc +main.files.File.PROPERTY.FILES.Servlet.PATHS : /javadoc/javax/servlet +main.files.File.PROPERTY.FILES.Servlet.DIRECTORY : ./src/javax/servlet/javadoc + + +# ======================================================================== +# Define the server instance named "proxy" +# ------------------------------------------------------------------------ +proxy.STACKS : root +proxy.LISTENER.all.ADDRS : 0.0.0.0:8081 + +# ======================================================================== +# Define the handler stack "root" in server "proxy" +# ------------------------------------------------------------------------ +proxy.root.HANDLERS : Log;Proxy;NotFound +proxy.root.PATHS : / +proxy.root.Log.PROPERTY.File : /tmp/demo.log +proxy.root.Log.PROPERTY.Append : True +proxy.root.Proxy.PROPERTY.PATHS : /;http;ftp diff --git a/Modules/sound/Player.java b/Modules/sound/Player.java new file mode 100644 index 0000000..05401ee --- /dev/null +++ b/Modules/sound/Player.java @@ -0,0 +1,37 @@ +/* +Player.java + * + * Copyright (c) 2001, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ + +package org.gzigzag.module; + +/** A (sound/video) player that doesn't need to know + * anything about zz. + */ +public interface Player { + // this needs more stuff, hashtable ? + // XXX getLength!!! -tjl + void init(String file); + void play(long from, long to, boolean loop); + void stop(); + long getCurrentOffset(); + +} diff --git a/Modules/sound/Recorder.java b/Modules/sound/Recorder.java new file mode 100644 index 0000000..0ba70b7 --- /dev/null +++ b/Modules/sound/Recorder.java @@ -0,0 +1,37 @@ +/* +Recorder.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ + +package org.gzigzag.module; + +public interface Recorder { + + // what is needed in here ??? + void init(String file, long offset); + + void start(); + + void stop(); + + long getCurrentOffset(); + +} diff --git a/Modules/sound/SimplePlayer.java b/Modules/sound/SimplePlayer.java new file mode 100644 index 0000000..1392f91 --- /dev/null +++ b/Modules/sound/SimplePlayer.java @@ -0,0 +1,65 @@ +/* +SimplePlayer.java + * + * Copyright (c) 2001, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.io.*; +import java.net.*; +import java.awt.*; + +/** A linux sound Player using GSM compression. Requires the associated native + * library. + */ + +public class SimplePlayer implements Player { + + private int handle; + + public void init(String file){ + handle = player_init(file); + } + + public void play( long from, long to, boolean loop){ + player_start(handle, from, to); + } + + public void stop(){ + player_stop(handle); + } + + + + public long getCurrentOffset(){ + return player_getCurrentOffset(handle); + } + + static { + System.loadLibrary("recorder"); + } + + private native int player_init(String file); + private native void player_start(int handle, long from, long to); + private native long player_getCurrentOffset(int handle); + private native void player_stop(int handle ); + +} diff --git a/Modules/sound/SimpleRecorder.java b/Modules/sound/SimpleRecorder.java new file mode 100644 index 0000000..54bc358 --- /dev/null +++ b/Modules/sound/SimpleRecorder.java @@ -0,0 +1,68 @@ +/* +SimpleRecorder.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.io.*; +import java.net.*; +import java.awt.*; + +/** + * Simple (linux) native recorder class to be used in + * sound stream handling in zz. + */ +public class SimpleRecorder implements Recorder { + + int handle = 0; + + // inits recorder with a output file name + public void init(String file, long offset){ + handle = recorder_init(file, offset); + } + + public void start(){ + recorder_start( handle ); + } + + + public void stop(){ + recorder_stop(handle); + } + + public long getCurrentOffset(){ + return recorder_getCurrentOffset(handle); + } + + + static { + System.loadLibrary("recorder"); + } + + private native void recorder_start(int handle); + + private native void recorder_stop(int handle ); + + private native int recorder_init(String file, long offset); + + private native long recorder_getCurrentOffset(int handle); +} diff --git a/Modules/sound/Sound.java b/Modules/sound/Sound.java new file mode 100644 index 0000000..ea65af3 --- /dev/null +++ b/Modules/sound/Sound.java @@ -0,0 +1,373 @@ +/* +Sound.java + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.io.*; +import java.net.*; +import java.awt.*; + +/** + * Should be broken to smaller pieces. + * @author Vesa Parkkinen + * + */ +public class Sound { + public static final String rcsid = "$Id: Sound.java,v 1.2 2001/03/27 20:43:25 tjl Exp $"; + + /* debugging */ + public static boolean dbg = true; + static final void p(String s) { if(dbg) ZZLogger.log(s); } + static final void pa(String s) { ZZLogger.log(s); } + + /** + * Static module used in gzigzag module loading. + */ + static public ZZModule module = new ZZModule() { + public void action( String id, ZZCell code, + ZZCell target, + ZZView v, ZZView cv, + String key, Point pt, + ZZScene xi) { + + p("Sound.module.action() " + id); + if( id.equals("PLAY") ) { + p("PLAYing..."); + instance.play(target); + } else if( id.equals("RECORD")){ + p("RECORDing..."); + // what ehis should mean ? + instance.record(target); + } else if ( id.equals("STOP")) { + p("STOPing..."); + instance.stop(); + } else if ( id.equals("CUT")){ + p("CUTing..."); + instance.cut(); + } else if ( id.equals("TAG")) { + p("TAGing..."); + instance.tag(target); + } else if ( id.equals("INIT")) { + p("INITing..."); + instance.init(target); + } + } + public ZOb newZOb(String id) { + p("Sound.module.newZOb(" + id + ")"); + return null; + } + }; + + static String stream = "SNDSTR"; + static String file = "/tmp/soundscroll"; + + static String d = "d.sound"; + static String dtag = "d.handle"; + static String dspan = "d.sound-span"; + static String dsessions = "d.sound-sessions"; + + static long duration = 2000000; + static String mod = "Sound"; + + static String[] ops = { //"INIT", + "PLAY", + "RECORD", + "STOP", + "CUT", + "TAG" + }; + + Recorder recorder = new SimpleRecorder(); + + public Span getSpan(){ + return null; + } + + public ZZCell getSpanAsCell(){ + return null; + } + + //************************************************************************ + //* private variables + //************************************************************************ + + private static Sound instance; + + static { + instance = new Sound(); + } + + // current offset from the start of the session + private long offset = 0; + + // offset of the end of the last span + private long lastOffset = 0; + private long sessionStart = 0; + + // are we playing at the moment + private boolean playing = false; + + // are we recording at the moment + private boolean recording = false; + + private Player player = null; + + private ZZCell last = null; + private ZZCell spanCell = null; + private ZZCell sessionCell = null; + + // THESE SHOULD COME FROM STRUCTURE + + private SoundScroll soundScroll = null; + // the session this stream belongs to + private ZZCell session = null; + // the input device associated with this stream. + private ZZCell inDevice = null; + // the input device associated with this stream. + private ZZCell outDevice = null; + + private ZZCell offsetCell = null; + + public Sound(){ + //t.start(); + pa("CONSTRUCTOR!!!"); + } + + ZZCell scrollCell = null; + + private void init(ZZCell c){ + // TODO: + // create a new window + // with soundvie + ZZDefaultSpace.addDimensionToDefaultDimlist(c, d); + ZZDefaultSpace.addDimensionToDefaultDimlist(c, dspan); + ZZDefaultSpace.addDimensionToDefaultDimlist(c, dsessions); + ZZDefaultSpace.addDimensionToDefaultDimlist(c, "d.handle"); + //soundScroll = new SoundScroll(stream, file, 1000); + //Scroll.register(stream, soundScroll); + for(int i = 0; i < ops.length; i++){ + c = c.N("d.2", 1); + c.setText(mod+"."+ops[i]); + } + addScroll(c); + scrollCell = ZZDefaultSpace.findScrollCell(c.getHomeCell(), stream); + soundScroll = (SoundScroll)Scroll.obtain( c.getSpace(), + stream); + if( spanCell != null ) + spanCell = scrollCell.N(dspan,1); + + p("SOUNDSCROLL = " + soundScroll); + } + + private void addScroll(ZZCell c){ + if( c==null ) return; + ZZCell home = c.getHomeCell(); + ZZCell d = home.findText("d.2", -1, "Scrolls"); + if( d == null ) { + d = home.N("d.2",-1); + d.setText("Scrolls"); + } + ZZCell x = d.findText("d.1", 1, stream); + if( x != null ) return ; + d = d.N("d.1",1); + d.setText(stream); + d = d.N("d.2",1); + d.setText(file); + d = d.N("d.2",1); + d.setText("Sound"); + d = d.N("d.2",1); + d.setText("1000000"); + d = d.N("d.2",1); + d.setText("offset"); + d = d.N("d.1",1); + d.setText("0"); + offsetCell = d; + } + + + //************************************************************************ + //* public methods + //************************************************************************ + /** + * + */ + public void record(ZZCell session){ + if( playing || recording ) return; + p("not recording or playing"); + // create a new scroll + if( soundScroll == null ) + soundScroll = (SoundScroll)Scroll.obtain( session.getSpace(), + stream); + //file = soundScroll.getFile(file); + + p("SOUNDSCROLL: " + soundScroll); + + if( scrollCell == null ) { + scrollCell = ZZDefaultSpace.findScrollCell(session.getHomeCell(), + stream); + } + if( offsetCell == null) { + pa("SCRCELL = " + scrollCell); + offsetCell = scrollCell.findText("d.2", 1, "offset"); + offsetCell = offsetCell.s("d.1",1); + } + if( spanCell ==null ){ + spanCell = scrollCell.N(dspan,1); + } + if( sessionCell == null ){ + sessionCell = scrollCell.h(dsessions, 1); + sessionCell = sessionCell.N(dsessions,1); + } + last = sessionCell; + + final long scOffset = Long.parseLong(offsetCell.getText()); + offset = scOffset; + p("are we recording yet... " + recording); + p("initializing"); + // XXX chech the offset + recorder.init("/tmp/soundscroll", scOffset); + p("initalized..."); + Thread t = new Thread() { + public void run() { + p("S REC Thread"); + recorder.start(); + offset = recorder.getCurrentOffset(); + p("offset = " + offset); + offsetCell.setText(""+ offset); + Span s = Span.create( + Address.streamOffs(stream, 0), + Address.streamOffs(stream, offset) + ); + spanCell.setSpan(s); + sessionCell.setSpan(s = Span.create( + Address.streamOffs(stream, scOffset), + Address.streamOffs(stream, offset) + )); + last.setSpan(s); + lastOffset = offset; + } + }; + t.start(); + last = last.N(d,1); + recording = true; + } + + public void play(){ + play(0); + } + + public void play(long off){ + if( ! (playing || recording )) ; // start to play + } + + public void play(ZZCell from ){ + p("play " + from); + + Span s = from.getSpan(); + if( s == null ) { + pa("Not a span cell!!!"); + return; + } + if( soundScroll == null ) + soundScroll = (SoundScroll)s.getStart().getScroll(from.getSpace()); + // get these from factory??? + player = new SimplePlayer(); + File f = soundScroll.getFile(); + p("FILE = " + f); + p("FILE = " + f.toString()); + player.init(f.toString()); + p("initialized...\n"); + final ZZCell fc = from; + Thread t = new Thread() { + public void run() { + p("PlayerThread"); + player.play(fc.getSpan().getStart().getOffs(), + fc.getSpan().getEnd().getOffs(), false); + } + }; + t.start(); + playing = true; + + } + + public void play(ZZCell from, Dimension d, int dir ){ + + } + + /** + * Create a new span cell from last cut to this cut and connect + * new cell to the stream cells. + */ + public void cut(){ + offset = recorder.getCurrentOffset(); + p("offset = " + offset); + Span s = Span.create( + Address.streamOffs(stream, lastOffset), + Address.streamOffs(stream, offset) + ); + p("SPAN = " +s ); + p("span.getText(): " + s.getString(last)); + + last.setSpan(s); + lastOffset = offset; + last = last.N(d,1); + } + + public void tag(ZZCell t){ + p( "target: " + t); + last.insert(dtag,1, t); + } + + + public void pause(){ + if( playing ){ + player.stop(); + playing = false; + return ; + } + + if( recording ){ + player.stop(); + recording = false; + return ; + } + } + + public void stop() { + if( playing ){ + player.stop(); + p("player stopped\n"); + playing = false; + return ; + } + + if( recording ){ + p("stopping recorder..."); + recorder.stop(); + recording = false; + p("recorder stopped\n"); + return ; + } + } + +} diff --git a/Modules/sound/gsm_def.h b/Modules/sound/gsm_def.h new file mode 100644 index 0000000..7433f8e --- /dev/null +++ b/Modules/sound/gsm_def.h @@ -0,0 +1,2 @@ +#define GSM_SAMPLE 160 * 2 +#define GSM_FRAME 33 * 2 diff --git a/Modules/sound/gsm_player.c b/Modules/sound/gsm_player.c new file mode 100644 index 0000000..1733b8b --- /dev/null +++ b/Modules/sound/gsm_player.c @@ -0,0 +1,247 @@ +/* +gsm_player.c + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ + + +/**************************************************** + * INCLUDES + ****************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jni.h" +#include "org_gzigzag_module_SimplePlayer.h" +#include "gsm_def.h" + +/**************************************************** + * DEFINES + ****************************************************/ +#define DEVICE "/dev/dsp" +#define DEFAULT_DSP_SPEED 8000 +#define DEFAULT_DSP_FRAG 0 +#define DEFAULT_DSP_SAMPLE +#define PLAYS 10 + + +#ifndef uint +#define uint unsigned int +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +#ifndef DEBUG_SOUND +#define DEBUG_SOUND 0 +#endif +#define DEBUG(s) if(DEBUG_SOUND)printf(s); + +/**************************************************** + * STRUCTS + ****************************************************/ +/** + * playing + * Struct to hold infomation about playing. + */ +typedef struct { + char *file; // file to read from + int audio; // handle to audio device + int speed; + int samplesize; + int fragsize; + int channels; // mono 1, stereo 2 + long offset; // bytes from beginning + int stop; + int format; +} Playing; + + +Playing *pls[PLAYS]; + +int cur_play = 0; + +/** + * Error handling + */ +void per(char *str){ + printf("** player error: %s\n", str); + perror("ERROR: " ); +} + +/** + * Creates a new playing structure, and increments + * curr_play by 1. + * @return a pointer to new Playing struvct or NULL + */ +Playing *new_playing(int *rn){ + Playing *r = (Playing *) malloc(sizeof(Playing)); + cur_play++; + pls[cur_play] = r; + *rn = cur_play; + return r; +} + + +int init_playing(Playing *rec){ + rec->file = "/tmp/soundscroll"; + rec->audio = 0; + rec->speed = 8000; + rec->samplesize = 8; + rec->fragsize = 0; // not used at the moment + rec->channels = 1; + rec->offset = 0; + return 0; +} + +/** + * Initializes the recording device. + */ +int init_playing_device(const char *file){ + + int rn = 0; + Playing *r = new_playing(&rn); + init_playing(r); + r->file = strdup(file); + r->stop = -1; + r->offset = 0; + DEBUG("init device\n"); + + if ( (r->audio = open(DEVICE, O_WRONLY) ) < 0 ) { + per("OPEN FAILED"); + return 0; + } + DEBUG("opened device\n"); + + ioctl(r->audio, SNDCTL_DSP_SAMPLESIZE, &r->samplesize); + + if ( ioctl(r->audio, SNDCTL_DSP_SETFMT, + &r->format) == -1 ) { + perror("ioctl format"); + } + + if (ioctl (r->audio, SNDCTL_DSP_SPEED, &r->speed) == -1){ + per("set speed failed"); + } + + if (ioctl(r->audio, SNDCTL_DSP_CHANNELS, &r->channels) == -1) { + per("SNDCTL_DSP_CHANNELS"); + return 0; + } + + return rn; + +} + + +/******************************************************************* + * INIT * + *******************************************************************/ +JNIEXPORT jint JNICALL Java_org_gzigzag_module_SimplePlayer_player_1init +(JNIEnv *env, jobject obj, jstring file){ + int rv=0; + const char *fn = (const char *)(*env)->GetStringUTFChars(env, file, 0); + rv = init_playing_device(fn); + (*env)->ReleaseStringUTFChars(env, file, fn); + return rv; +} + + +/******************************************************************* + * STOP * + *******************************************************************/ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimplePlayer_player_1stop +(JNIEnv *env, jobject obj, jint handle){ + Playing *r = pls[handle]; + if ( r == NULL) return ; + DEBUG("native STOP\n"); + r->stop = 1; +} + +/******************************************************************* + * START * + *******************************************************************/ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimplePlayer_player_1start +(JNIEnv *env, jobject obj, jint handle, jlong from, jlong to){ + int fd = 0; + gsm_frame buf; + long f = from; + long t = to; + int g=0; + int i; + Playing *r = pls[handle]; + unsigned char accbuf[160]; + gsm gsm = gsm_create(); + gsm_signal gsm_out[160]; + + DEBUG("starting...\n"); + + if ((fd = open (r->file, O_RDONLY)) == -1){ + per("open failed"); + return; + } + + lseek(fd, f, SEEK_SET); + printf("to= %ld\n", t); + r->offset = f; + while (r->stop < 1 && r->offset < t){ + if (read (fd, (char *)buf, sizeof(buf)) != sizeof(buf)){ + per("read failed"); + close(fd); + close(r->audio); + return; + } + + if( gsm_decode(gsm, buf, gsm_out) < 0){ + perror("error decoding..."); + return ; + } + + for(g=0;g<160;g++){ + i=(int)gsm_out[g]+32768; + i>>=8; + /*gsm_out[g]=(unsigned char)i;*/ + accbuf[g]=(unsigned char)i; + } + + if ( (write (r->audio, accbuf, sizeof(accbuf))) != sizeof(accbuf)){ + per("write failed"); + close(fd); + close(r->audio); + return; + } + r->offset += sizeof(buf); + } /* While */ + + if (fd != 1) + close (fd); + + close( r->audio ); + + DEBUG("played\n"); +} diff --git a/Modules/sound/gsm_recorder.c b/Modules/sound/gsm_recorder.c new file mode 100644 index 0000000..1a824ed --- /dev/null +++ b/Modules/sound/gsm_recorder.c @@ -0,0 +1,240 @@ +/* +gsm_recorder.c + * + * Copyright (c) 2000, Ted Nelson, Tuomas Lukka and Vesa Parkkinen + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ +/** + * simple gsm recorder + */ + + +/**************************************************** + * INCLUDES + ****************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "jni.h" +#include "org_gzigzag_module_SimpleRecorder.h" +#include "gsm_def.h" + +/**************************************************** + * DEFINES + ****************************************************/ +#define DEVICE "/dev/dsp" +#define DEFAULT_DSP_SPEED 8000 +#define DEFAULT_DSP_FRAG 0 +#define DEFAULT_DSP_SAMPLE +#define RECS 10 +#define READ_BLOCK 1280 +#define BUFFER_SIZE 20 * READ_BLOCK +#define GSM_RECORDER_DEBUG 1 +//#define ENCODED_SIZE 20 * READ_BLOCK + +#ifndef uint +#define uint unsigned int +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +#ifndef DEBUG_SOUND +#define DEBUG_SOUND 0 +#endif + +#define DEBUG(s) if(DEBUG_SOUND)printf(s); +/**************************************************** + * STRUCTS + ****************************************************/ + +/** + * Recording + * Struct to hold infomation about recordings. + */ +typedef struct { + + char *file; // file to save to + int audio; // handle to audio device + int speed; + int samplesize; + int fragsize; + int channels; // mono 1, stereo 2 + ulong offset; // bytes from beginning + int format; + int stop; + +} Recording; + +Recording *recs[RECS]; +int cur_rec = 0; + +/** + * + */ +int init_recording(Recording *rec){ + rec->file = "/tmp/sndscroll"; + rec->audio = 0; + rec->speed = 8000; + rec->samplesize = 8; + rec->fragsize = 0; // not used at the moment + rec->channels = 1; + rec->offset = 0; + rec->stop = 0; + return 0; +} + +/** + * Creates a new recording structure, and increments + * curr_rec by 1. + * @return a pointer to new Recording struvct or NULL + */ +Recording *new_recording(int *rn){ + Recording *r = (Recording *) malloc(sizeof(Recording)); + cur_rec++; + recs[cur_rec] = r; + *rn = cur_rec; + return r; +} + +/** + * Initializes the recording device. + */ +int init_device(const char *file){ + int rn = 0; + Recording *r = new_recording(&rn); + init_recording(r); + r->file = strdup(file); + r->stop = -1; + + DEBUG("init device\n"); + + if ( (r->audio = open(DEVICE, O_RDONLY) ) < 0 ) { + perror("OPEN FAILED"); + } + + DEBUG("opened device\n"); + + if( ioctl(r->audio, SNDCTL_DSP_SAMPLESIZE, &r->samplesize) == -1){ + perror("SNDCTL_DSP_SAMPLESIZE"); + return -1; + } + + if (ioctl(r->audio, SNDCTL_DSP_CHANNELS, &r->channels) == -1) { + perror("SNDCTL_DSP_CHANNELS"); + return -1; + } + + if (ioctl (r->audio, SNDCTL_DSP_SPEED, &r->speed) == -1){ + perror("set speed failed"); + } + DEBUG("initialized device\n"); + return rn; +} + + +/******************************************************************* + * GET CURRENT OFFSET * + *******************************************************************/ +JNIEXPORT jlong JNICALL +Java_org_gzigzag_module_SimpleRecorder_recorder_1getCurrentOffset +(JNIEnv *env, jobject obj , jint handle){ + Recording *r = recs[handle]; + if( r == NULL ) return 0; + return r->offset; +} + +/******************************************************************* + * INIT * + *******************************************************************/ +JNIEXPORT jint JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1init +(JNIEnv *env, jobject obj, jstring file, jlong offset){ + int rv=0; + const char *fn = (const char *)(*env)->GetStringUTFChars(env, file, 0); + rv = init_device(fn); + (*env)->ReleaseStringUTFChars(env, file, fn); + recs[rv]->offset = offset; + return rv; +} + +/******************************************************************* + * STOP * + *******************************************************************/ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1stop +(JNIEnv *env, jobject obj, jint handle){ + Recording *r = recs[handle]; + if ( r == NULL) return ; + r->stop = 1; +} + +/******************************************************************* + * START * + *******************************************************************/ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1start +(JNIEnv *env, jobject obj, jint handle){ + + int fd = 0; + char *audiobuf; + + gsm gsm = gsm_create(); + gsm_signal sample[160]; + gsm_frame frame; + + Recording *r = recs[handle]; + + if ((fd = open (r->file, O_WRONLY | O_CREAT, 0666)) == -1){ + perror("recorder start: open failed"); + return ; + } + + lseek(fd, r->offset, SEEK_SET); + + while ( r->stop < 1 ){ + read (r->audio, sample, sizeof(sample) ); + gsm_encode(gsm, sample, frame); + + // write + if (write (fd, frame, sizeof(frame)) != sizeof(frame)){ + perror("write failed"); + //exit (-1); + return ; + } + r->offset += sizeof(frame); + } + if (fd != 1) + close (fd); + + close( r->audio ); + + gsm_destroy(gsm); + + printf("recorded\n"); +} diff --git a/Modules/sound/org_gzigzag_module_SimplePlayer.h b/Modules/sound/org_gzigzag_module_SimplePlayer.h new file mode 100644 index 0000000..17e2db7 --- /dev/null +++ b/Modules/sound/org_gzigzag_module_SimplePlayer.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_gzigzag_module_SimplePlayer */ + +#ifndef _Included_org_gzigzag_module_SimplePlayer +#define _Included_org_gzigzag_module_SimplePlayer +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_gzigzag_module_SimplePlayer + * Method: player_init + * Signature: (Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_gzigzag_module_SimplePlayer_player_1init + (JNIEnv *, jobject, jstring); + +/* + * Class: org_gzigzag_module_SimplePlayer + * Method: player_start + * Signature: (IJJ)V + */ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimplePlayer_player_1start + (JNIEnv *, jobject, jint, jlong, jlong); + +/* + * Class: org_gzigzag_module_SimplePlayer + * Method: player_getCurrentOffset + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_org_gzigzag_module_SimplePlayer_player_1getCurrentOffset + (JNIEnv *, jobject, jint); + +/* + * Class: org_gzigzag_module_SimplePlayer + * Method: player_stop + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimplePlayer_player_1stop + (JNIEnv *, jobject, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Modules/sound/org_gzigzag_module_SimpleRecorder.h b/Modules/sound/org_gzigzag_module_SimpleRecorder.h new file mode 100644 index 0000000..49f086c --- /dev/null +++ b/Modules/sound/org_gzigzag_module_SimpleRecorder.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_gzigzag_module_SimpleRecorder */ + +#ifndef _Included_org_gzigzag_module_SimpleRecorder +#define _Included_org_gzigzag_module_SimpleRecorder +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_gzigzag_module_SimpleRecorder + * Method: recorder_start + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1start + (JNIEnv *, jobject, jint); + +/* + * Class: org_gzigzag_module_SimpleRecorder + * Method: recorder_stop + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1stop + (JNIEnv *, jobject, jint); + +/* + * Class: org_gzigzag_module_SimpleRecorder + * Method: recorder_init + * Signature: (Ljava/lang/String;J)I + */ +JNIEXPORT jint JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1init + (JNIEnv *, jobject, jstring, jlong); + +/* + * Class: org_gzigzag_module_SimpleRecorder + * Method: recorder_getCurrentOffset + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_org_gzigzag_module_SimpleRecorder_recorder_1getCurrentOffset + (JNIEnv *, jobject, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Modules/test/README b/Modules/test/README new file mode 100644 index 0000000..2da6607 --- /dev/null +++ b/Modules/test/README @@ -0,0 +1,2 @@ +Some classes for testing various things. Mostly useful only for +developers. diff --git a/Modules/test/TestClang1.java b/Modules/test/TestClang1.java new file mode 100644 index 0000000..4af2c63 --- /dev/null +++ b/Modules/test/TestClang1.java @@ -0,0 +1,100 @@ +/* +TestClang1.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import org.gzigzag.clang.*; +import java.util.*; +import java.awt.*; + +class ELIFJSEF { +} + +/** A small tester for Clang. + */ + + +public class TestClang1 { +public static final String rcsid = "$Id: TestClang1.java,v 1.9 2000/10/18 14:35:32 tjl Exp $"; + public static final boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + ZZCell viewCursor = ZZCursorReal.get(view.getViewcell()); + p("TESTCLANG ACTION!"); + if(id.equals("1")) { + test1(viewCursor); + } else { + pa("UNKNOWN TESTCLANG1 COMMAND "+id); + } + p("TESTCLANG ACTION RETURNS!"); + } + }; + + static void test1(ZZCell curs) { + + ZZClang1 clang = new ZZClang1(); + ZZClangOp[] ops = ZZClangOps.getOps1(); + for(int i = 0; i < ops.length; i++) + clang.addOp(ops[i]); + + ZZCell main = curs.N("d.2", 1); + // Goal of script: connect these two. + ZZCell c1 = main.N("d.1", 1); + c1.setText("c1"); + ZZCell c2 = c1.N("d.1", 1); + c1.setText("c2"); + + ZZCell func = main.N("d.2", 1); + func = func.N("d.1", 1); + func.setText("func"); + ZZCell par = func.N("d.1", 1); + par.setText("c"); + ZZCell cmd = func.N("d.2", 1); + cmd.setText("connect"); + ZZCell param = cmd.N("d.1", 1); + par.insert("d.clone", 1, param); + param = param.N("d.1", 1); + param.setText("d.2"); + param = param.N("d.1", 1); + par.insert("d.clone", 1, param); + param = param.N("d.2", 1); + param.setText("step"); + param = param.N("d.1", 1); + param.setText("d.1"); + param = param.N("d.1", 1); + param.setText("1"); + + p("TESTCLANG CLANGEXEC!"); + + // clang.exec(func, null, new ZZCell[] { c1 }); + + + } + +} + diff --git a/Modules/test/TestHuge.java b/Modules/test/TestHuge.java new file mode 100644 index 0000000..31a6e28 --- /dev/null +++ b/Modules/test/TestHuge.java @@ -0,0 +1,55 @@ +/* +TestHuge.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + + +package org.gzigzag.module; + +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +public class TestHuge { +public static final String rcsid = "$Id: TestHuge.java,v 1.4 2000/10/18 14:35:32 tjl Exp $"; + + static public ZZModule module = new ZZModule() { + public void action(String id, ZZCell code, + ZZCell target, + ZZView v, ZZView cv, + String key, Point pt, + ZZScene xi) { + if(id.equals("ADDTREE")) { + ZZCell h = target.getHomeCell(); + h = h.h("d.1", 1); + ZZCell n = null; + int nth = 1; + for(; h != null; h=h.s("d.2", 1)) { + ZZCell m = h.N("d.1", 1); + m.setText(""+(nth++)); + if(n != null) n.connect("d.2", 1, m); + n = m.N("d.2", 1); + n.setText(""+(nth++)); + } + } + } + }; +} diff --git a/Modules/test/TestUndo.java b/Modules/test/TestUndo.java new file mode 100644 index 0000000..657033a --- /dev/null +++ b/Modules/test/TestUndo.java @@ -0,0 +1,210 @@ +/* +TestUndo.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + +package org.gzigzag; +import java.io.*; + +public class TestUndo { +String rcsid = "$Id: TestUndo.java,v 1.8 2000/11/30 08:44:33 ajk Exp $"; + + public static final boolean dbg = true; + final static void p(String s) { if(dbg) System.out.println(s); } + + /* + + static void printdim(ZZDimension d, int max) { + for(int i=1; i<=max; i++) { + p(i+"\t+"+ d.s(""+i, 1, null)+ + "\t-"+ d.s(""+i, -1, null)); + } + p(""); + } + + static String ct2str(Object o) { + if(o instanceof String) + return "'"+o+"'"; + else if(o instanceof Span) + return "SPAN: "+o; + else if(o == null) + return "null"; + throw new Error("Invalid content "+o); + } + + static void printct(ContentStore st, int max) { + for(int i=1; i<=max; i++) { + p(i+"\t"+ct2str(st.get(""+i))); + } + p(""); + } + + public static void main(String[] argv) { + { + ZZCacheDimension d = new ZZCacheDimension(); + UndoList ul = new UndoList(42); + d.setUndoList(ul); + + ZZDimStorer pstor = new ZZDimStorer() { + public void storeConnect(String a, String b) { + p("Storeconn: "+a+" "+b); + } + public void storeDisconnect(String a, int dir) { + p("Storedisc: "+a+" "+dir); + } + }; + + ContentStorer cstor = new ContentStorer() { + public void putContent(String id, Object ct) { + p("StoreCont: "+id+" "+ct2str(ct)+""); + } + }; + + d.connect("1", "2"); + d.connect("3", "4"); + + ul.stamp(); + printdim(d, 4); + + ul.undo(); + p("undo:"); + printdim(d, 4); + + ul.redo(); + p("redo:"); + printdim(d, 4); + + p(" Next, more difficult test."); + + d.disconnect("1", 1); + d.connect("1", "3"); + + ul.stamp(); + printdim(d, 4); + + ul.undo(); + p("undo:"); + printdim(d, 4); + + ul.undo(); + p("undo:"); + printdim(d, 4); + + ul.redo(); + p("redo:"); + printdim(d, 4); + + ul.redo(); + p("redo:"); + printdim(d, 4); + + p("Next, whether commit does the right ops..."); + + d.startCommit(); + ul.commit(); + d.endCommit(pstor); + + p("Commit finished"); + + p("More edits"); + + d.disconnect("3", 1); + d.connect("2", "4"); + printdim(d, 4); + + p("Commit ops..."); + d.startCommit(); + ul.commit(); + d.endCommit(pstor); + p("Commit finished"); + + p("Next, we'll test the simple file format."); + + SimpleDimFile f = new SimpleDimFile(); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + + f.startWrite(new DataOutputStream(bo)); + + f.storeConnect("Foo", "Bar"); + f.storeConnect("1", "2"); + f.storeDisconnect("a", 1); + f.storeDisconnect("b", -1); + f.storeDisconnect("3", 1); + f.endWrite(); + + byte[] bytes = bo.toByteArray(); + bo.reset(); + + p("Wrote ops. Now read."); + // f.read(new DataInputStream(new ByteArrayInputStream(bytes)), pstor); + + + p("Finally, test the content storage as well"); + + ZZCacheContentStore ccs = new ZZCacheContentStore(); + ccs.setUndoList(ul); + + ul.stamp(); + + ccs.put("1", "foo"); + ccs.put("2", "bar"); + ccs.put("3", Span.parse("1.5:1.8")); + + ul.stamp(); + ccs.put("2", "txt"); + ul.stamp(); + printct(ccs, 4); + + ul.undo(); + p("Undo: "); + printct(ccs, 4); + + ul.undo(); + p("Undo: "); + printct(ccs, 4); + + ul.redo(); + p("Redo: "); + printct(ccs, 4); + + ul.redo(); + p("Redo: "); + printct(ccs, 4); + + SimpleContentFile cf = new SimpleContentFile(); + cf.startWrite(new DataOutputStream(bo)); + + cf.putContent("A", "FOO"); + cf.putContent("B", "bar"); + cf.putContent("C", Span.parse("1.5:1.8")); + cf.endWrite(); + bytes = bo.toByteArray(); + bo.reset(); + + p("Wrote txts; read:"); + // cf.read(new DataInputStream(new ByteArrayInputStream(bytes)), cstor); + + + } + + } + */ +} diff --git a/Modules/textcloud/TextCloud.zob b/Modules/textcloud/TextCloud.zob new file mode 100644 index 0000000..990d1fc --- /dev/null +++ b/Modules/textcloud/TextCloud.zob @@ -0,0 +1,353 @@ +/* +TextCloud.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; +import java.io.*; + +/** A text cloud. + */ + +public class TextCloud implements FlobView, FlobSet.DragCursor, ZOb { +public static final String rcsid = "$Id: TextCloud.zob,v 1.7 2000/12/11 09:03:03 raulir Exp $"; + public static boolean dbg = false; + static void p(String s) { if(dbg) System.out.println(s); } + static void pa(String s) { System.out.println(s); } + + static RankTextView vr; + static SimpleBeamer bmr; + + STRUCTPARAMS { + } + + /** The horizontal and vertical offsets of the insertion cursor when + * dragging. + */ + static final int vcursx = -16, vcursy = -16; + + static ZZCell dragItem; + static int dragXOffs; static int dragYOffs; + + + public boolean accept(Object o) { + if(!(o instanceof ZZCursor)) return false; + ZZCursor c = (ZZCursor) o; + if(c.getOffs() == c.NO_OFFSET) return false; + return true; + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + if(vr == null) { + vr = new RankTextView(); + vr.readParams(null); + + bmr = new SimpleBeamer(); + bmr.readParams(null); + } + + // ZZAbstractView + ZZCell cloudmain = ZZCursorReal.get(view); + ZZCell curs = ZZCursorReal.get(cloudmain); + // p("TEXTCLOUD RASTER"); + if(cloudmain == null) return; + for(ZZCell item = cloudmain.s("d.1", 1); + item != null; + item = item.s("d.1", 1)) { + int[] c = ZZDefaultSpace.paramIntA(item, "Coords", null, 2); + if(c==null) { + p("NULL COORDS!"); + continue; + } + ZZCell vstream = + item.s("d.2", 1).s("d.1",1); + VStream.check(vstream); + + vr.raster(into, vstream, 0, false, c[0], c[1]); + if(item == dragItem) { + // Draw the arrow + + into.add(new ArrowDecor(c[0], c[1], + c[0]+vcursx, c[1]+vcursy, Color.red, 1)); + into.setDragCursor(this, c[0]+vcursx, c[1]+vcursy); + } + } + + bmr.decorate(into, "", null); + } + + + + static void stopdrag(ZZScene xi) { + p("StopDrag: "+dragItem); + if(dragItem == null) return; + // Check if the virtual cursor falls on something. + // Use itemcoords to get the UL corner of the item + // instead of mouse. + Point it = itemCoords(dragItem); + if(it == null || xi == null) { // Something went out from under us + dragItem = null; + return; + } + Object ob = xi.getObjectAt(it.x+vcursx, it.y+vcursy); + p("StopDrag item: "+ob); + if(!(ob instanceof ZZCursor)) return; + + // YES! INSERT! Delete the dragged item first. + ZZCursor p = (ZZCursor)ob; + ZZCell vstr = itemVStream(dragItem); + dragItem.delete(); + dragItem = null; + + VStream.assimilate(p, vstr); + + // XXX Should surround the inserted piece with cuts + // so that it's easy to take out again. + } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + + ZZCell viewCell = view.getViewcell(); + ZZCell cloudmain = ZZCursorReal.get(viewCell); + ZZCell viewCursor = null; + if(cloudmain!=null) viewCursor = ZZCursorReal.get(viewCell); + + Object ob = null; + if(pt != null && xi != null) + ob = xi.getObjectAt(pt.x, pt.y); + + + if(!id.equals("Dragged")) stopdrag(xi); + + p("Text action! '"+id+"' key: "+key); + if(id.equals("NEWITEM")) { + } else if(id.equals("TESTWIN")) { + + + ZZCell cloudhome = code.getHomeCell().N("d.2", -1); + cloudhome.setText("TextCloud"); + ZZCell n = newItem(cloudhome, 50,50, null); + ZZCell vs1 = n.s("d.2", 1).s("d.1", 1); + ZZCursor p = VStream.start(vs1); + VStream.insert(p,"TESTTEXT 1"); + p = VStream.start(vs1); + p = VStream.add(p, 4); + VStream.insert(p,"FOO"); + + ZZCell rc = code.getHomeCell().N("d.2", -1); + ZZCell rl = rc.N("d.1", 1); + rl.connect("d.2", 1, rl); + rl.setText("Textcloud"); + ZZCell rastname = rl.N("d.1", 1); + rastname.setText("TextCloud.Normal"); + + // Bindings + ZZCell bindhome = code.getHomeCell().N("d.2", -1); + bindhome.setText("TCBind"); + bindhome = bindhome.N("d.1", 1); + ZZDefaultSpace.mkCorner(bindhome, actions); + + + ZZCell v = ZZDefaultSpace.newToplevelView(rc.getSpace(), + "textcloud", 100, 100, 600, 600, + rl, bindhome, + null, null, + null, + new Color(0xFFFFB1)); + ZZCursorReal.set(v,cloudhome); + ZZCursorReal.set(cloudhome,vs1); + + } else + + // Now, the real actions + if(id.equals("NewOrCurs")) { + // Now, ob is either a Point or a ZZCursor - for other + // things we don't care. + // XXX This should be more OO!!! + if(ob == null && pt != null) { + p("Vc: "+viewCursor); + p("CM: "+cloudmain); + ZZCell item = newItem(cloudmain, pt.x, pt.y, null); + ZZCursor p = itemVStreamStart(item); + VStream.setCursorFromPos(cloudmain, p); + } else if(ob instanceof ZZCursor) { + VStream.setCursorFromPos(cloudmain, (ZZCursor) ob); + } else + p("Strange xi param "+ob); + + } else if(id.equals("Insert")) { + if(key == null) return; + if(key.length() > 1) { + p("Composite key: "+key); + return ; + } + VStream.insert(VStream.posFromCursor(cloudmain), key); + } else if(id.equals("StartDrag") + || id.equals("StartDragCopy")) { + if(!(ob instanceof ZZCursor)) { + dragItem = null; + return; + } + ZZCursor pos = (ZZCursor)ob; + // Now, if we can cut, we cut! + ZZCell nvstream = null; + if(id.equals("StartDragCopy")) + nvstream = VStream.separateCopy(pos); + else + nvstream = VStream.separate(pos); + if(nvstream != null) { + ZZCell item = newItem(cloudmain, pt.x-10, pt.y-10, nvstream); + // We did cut out a part. Whew! + dragXOffs = 0; + dragYOffs = 0; + dragItem = item; + } else { + dragItem = itemFromVStream(pos.get()); + } + + Point ip = itemCoords(dragItem); + if(ip==null) { p("No item coord"); return; } + if(pt==null) { p("No startdrag coord"); return; } + dragXOffs = ip.x - pt.x;; + dragYOffs = ip.y - pt.y;; + } else if(id.equals("Dragged")) { + if(dragItem == null) return; + if(pt==null) { p("No drag coord"); return; } + setItemCoords(dragItem, pt.x + dragXOffs, pt.y + dragYOffs); + + } else if(id.equals("StopDrag")) { + stopdrag(xi); + return; + } else if(id.equals("Cut")) { + if(!(ob instanceof ZZCursor)) return; + // Put in a cut mark. XXX HOW? + VStream.cut((ZZCursor)ob); + } else if(id.equals("Backspace")) { + VStream.backspace(VStream.posFromCursor(cloudmain)); + } else if(id.equals("ClearCuts")) { + VStream.clearcuts(VStream.posFromCursor(cloudmain)); + // p("Clear cuts: "+ob); + // if(!(ob instanceof ZZCursor)) return; + // VStream.clearcuts((ZZCursor)ob); + } else if(id.equals("DeleteItem")) { + if(!(ob instanceof ZZCursor)) return; + ZZCell item = itemFromVStream(((ZZCursor)ob).get()); + item.delete(); + } + + + } + + public ZOb newZOb(String id) { + if(id.equals("Normal")) { + return new TextCloud(); + } + return null; + } + }; + + static String[][] actions = { + { "MouseClicked1", "TextCloud.NewOrCurs" }, + { "MouseClicked3", "TextCloud.Cut" }, + { "Ctrl-MouseClicked3", "TextCloud.DeleteItem" }, + { "MouseStartDrag", "TextCloud.StartDrag" }, + { "Shift-MouseStartDrag", "TextCloud.StartDragCopy" }, + { "MouseDragged1", "TextCloud.Dragged" }, + { "Shift-MouseDragged1", "TextCloud.Dragged" }, + { "MouseReleased1", "TextCloud.StopDrag" }, + { "Shift-MouseReleased1", "TextCloud.StopDrag" }, + { "Backspace", "TextCloud.Backspace" }, + { "Esc", "TextCloud.ClearCuts" }, + { "DEFAULT", "TextCloud.Insert" } + }; + + static public ZZCell newItem(ZZCell cloud, int x, int y, ZZCell vstream) { + ZZCell item = cloud.N("d.1", 1); + ZZCell c = item.N("d.2", 1); + c.setText("Coords"); + ZZCell n1 = c.N("d.1", 1); + n1.setText(""+x); n1 = n1.N("d.1", 1); + n1.setText(""+y); + // Note now going up + c = c.N("d.2", -1); + Scroll s = cloud.getSpace().getStringScroll(); + // Width 0 - I wonder how this will work.. + if(vstream != null) { + c.connect("d.1", 1, vstream); + } else { + VStream.create(c, "d.1", 1, Span.create( + Address.scrollOffs(s, 1), + Address.scrollOffs(s, 0) + )); + } + return item; + } + + static Point itemCoords(ZZCell item) { + int[] c = ZZDefaultSpace.paramIntA(item, "Coords", null, 2); + if(c==null) { + p("NULL COORDS!"); + return null; + } + return new Point(c[0], c[1]); + } + static void setItemCoords(ZZCell item, int x, int y) { + ZZCell c = ZZDefaultSpace.findInheritableParam(item, "Coords"); + c = c.s("d.1", 1); c.setText(""+x); + c = c.s("d.1", 1); c.setText(""+y); + } + + static public ZZCell itemVStream(ZZCell item) { + return item.s("d.2", 1).s("d.1", 1); + } + static public ZZCursor itemVStreamStart(ZZCell item) { + return VStream.start(itemVStream(item)); + } + static public ZZCell itemFromVStream(ZZCell c) { + return c.h("d.2", -1) + .h("d.1", -1) + .h("d.2", -1); + } + + static public ZZCell cloudHomeFromVStream(ZZCell c) { + ZZCell cloudmain = c.h("d.2", -1) + .h("d.1", -1) + .h("d.2", -1) + .h("d.1", -1); + if(! cloudmain.getText().equals("TextCloud")) { + p("NOT CLOUD!"); + return null; + } + return cloudmain; + } + + +} + + +// vim: set syntax=java : diff --git a/Modules/virtualcommunity/MessageFlobFactory.zob b/Modules/virtualcommunity/MessageFlobFactory.zob new file mode 100644 index 0000000..377a438 --- /dev/null +++ b/Modules/virtualcommunity/MessageFlobFactory.zob @@ -0,0 +1,546 @@ +/* +MessageFlobFactory.zob + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Rauli Ruohonen + */ + +package org.gzigzag.module; +import org.gzigzag.module.multimedia.*; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; + +public class MessageFlobFactory implements FlobFactory, ZOb { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + private String d_image = "d.images"; + private String d_text = "d.text"; + private String d_author = "d.author"; + private String d_handle = "d.kahva"; + + private MediaFlobFactory mediafact=new MediaFlobFactory(); + private FTextLayouter ftext=new FTextLayouter(); + + SceneFlob mysflob = null; + + VirtualCommunity vc= null; + + STRUCTPARAMS { + /* In pixels. */ + int imgtxt_separator + = 0; + /* Originally 1/Ph = img_h/txt_h =~ 0.618. (Ph = Golden Ratio) */ + float imgtxt_min_ratio + = (float)(2.0/(Math.sqrt(5.0)+1.0)); + ScalableFont font + = new ScalableFont("SansSerif", Font.PLAIN, 12); + /* color of the author blob */ + Color authorColor + = Color.yellow.brighter(); + /* color of the message blob */ + Color messageColor + = new Color(0xffff8c); + Color auth_bg + = new Color(0xffff28); + int border + = 3; + int clipborder + = 2; + } + + public MessageFlobFactory(VirtualCommunity vc){ + + this.vc = vc; + } + public MessageFlobFactory(){ + + + } + + private Color back = Color.white; + + private FText makeFText(ZZCell c, ZZCell hc,float fract) { + Vector a=new Vector(); + int scale=(int)(fract*1000); + Font f=font.getFont(scale); + FontMetrics fm=font.getFontMetrics(scale); + Color fg=Color.black;//,bg=Color.white; + LoopDetector l=new LoopDetector(); + c = c.s(d_text,1); + Color fgt = fg; + while(c!=null) { + fgt = fg; + l.detect(c); + /*if( c.s(d_handle,1) != null || c.s(d_handle,-1) != null){ + fgt = Color.red; + }*/ + a.addElement(new FText.CellPart(c,c,0,-1,f,fm,back,fgt)); + //a.addElement(new FText.StringPart(c.getText(),f,fm,back,fgt)); + c=c.s(d_text); + } + return new FText(a); + } + + public SceneFlob getSFlob(){ + + return mysflob; + } + + private int cacheW = -1; + private Dimension cacheTxt; + private ZZCell cacheC; + private float cacheFract; + private void getSizes(ZZCell c,float fract,int w,int h,Dimension img, + Dimension txt) { + final int MAGIC=2147483647; + ZZCell imgc=c.h(d_image,true); + ZZCell textc=c.s(d_text); + img.width=0; img.height=0; txt.width=0; txt.height=0; + /* Calculate the maximum sizes for both image and text */ + if(imgc!=null) img.setSize(mediafact.getSize(imgc,fract)); + float aspect=img.width*1.0f/img.height; + if(textc!=null) { + if (cacheW == w && cacheFract == fract && c.equals(cacheC)) + txt.setSize(cacheTxt); + else { + cacheTxt = ftext.place(null,makeFText(c,c,fract), + new Rectangle(0,0,w,MAGIC), + 1,1,0,0xdeadbeef,false).getSize(); + cacheW = w; cacheC = c; cacheFract = fract; + txt.setSize(cacheTxt); + } + } + // Subj. + Auth. + txt.height += (font.getFontMetrics((int)(1000 * fract)). + getHeight())*2; + if (imgc == null) { + txt.height = h; + return; + } + if (textc == null) { + img.height=h-txt.height; + img.width=(int)(img.height*aspect); + if(img.width>w) { + img.width=w; + img.height=(int)(img.width/aspect); + } + txt.height = h-img.height; + return; + } + h-=imgtxt_separator; + float imgtxt_ratio=(h-txt.height)/txt.height; // Text size constant + p("it_rat="+imgtxt_ratio); + if(imgtxt_ratio 0) x = p.x - d.width; + if(yalign < 0) y = p.y; + if(yalign > 0) y = p.y - d.height; + return makeFlob(into, c, handleCell, fract, x, y, + depth, d.width, d.height); + } + + public Flob centerFlob(FlobSet into, + ZZCell c, ZZCell handleCell, + float fract, Point p, int xalign, int yalign, + int depth) { + return centerFlob(into, c, handleCell, fract, p, xalign, yalign, + depth, null); + } + + public Flob makeSubject(FlobSet into, + ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, + int w, Flob parent, int mh) { + + if (mh > 100) mh = 100; + Flob sc = new SubjCell(x,y,depth,w,mh,c, handleCell, fract); + sc.setParent(parent); + into.add(sc); + return sc; + + } + + public Flob makeAuthor(FlobSet into, + ZZCell c, ZZCell handleCell, + float fract, + int x, int y, int depth, int w, + float xfract, float yfract, Flob parent, int mh) { + + if (mh > 100) mh = 100; + Flob ac = new AuthCell(x,y,depth,w,mh,c, handleCell, fract); + ac.setParent(parent); + into.add(ac); + return ac; + + } + + /** + * Flob for message subjects + */ + class SubjCell extends Flob { + + int ascent; + float fr; + ZZCell handle; + + public SubjCell(int x, int y, int d, int w, int h, ZZCell c, ZZCell hc, + float fract){ + super(x,y,d,w,h,c); + Font f = font.getFont((int)(1000 * fract)); + FontMetrics fm = font.getFontMetrics((int)(1000 * fract)); + ascent = fm.getAscent(); + this.h = fm.getHeight(); + if (this.h > h) this.h = h; + //this.w = fm.stringWidth("Subject: " +c.getText()); + fr = fract; + handle = hc; + //p("FR = " + fr); + } + + public void renderInterp(Graphics g, float fract) { return; } + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + /*ZZDrawingJ2D drw = null; + if (ZZDrawing.instance instanceof ZZDrawingJ2D) + drw = (ZZDrawingJ2D)ZZDrawing.instance; + if (drw != null) { + drw.setFIXME(false); + drw.setQuality(g); + }*/ + FontMetrics fm = font.getFontMetrics((int)(1000 * fr)); + Color old = g.getColor(); + g.setFont(font.getFont((int)(fr*1000))); + g.setColor(auth_bg); + Rectangle asd=g.getClipBounds(); + g.setClip(mx-clipborder,my-clipborder,mw+clipborder*2,mh+clipborder*2); + g.fillRect(mx,my,mw,mh); + g.setColor(old); + /*if (drw != null) { + drw.setFIXME(true); + drw.setQuality(g); + }*/ + if( fm.stringWidth("Subject: " + c.getText()) > mw ) + g.drawString( c.getText(), mx,my+ascent); + else g.drawString("Subject: " + c.getText(), mx,my+ascent); + //g.drawLine(mx, my+h, mx+w, my+h); + g.setClip(asd); + } + + public Object hit(int x0, int y0) { + if( x0 >= x && y0 >= y && x0 < x+w && y0 < y+h ) + return handle; + return null; + } + + } + + + /** + * Flob for message auth + */ + class AuthCell extends Flob { + + int ascent; + int height; + ZZCell handle; + + float fr = 1.0f; + + public AuthCell(int x, int y, int d, int w, int h, ZZCell c, ZZCell hc, + float fract){ + super(x,y,d,w,h,c); + Font f = font.getFont((int)(1000 * fract)); + FontMetrics fm = font.getFontMetrics((int)(1000 * fract)); + ascent = fm.getAscent(); + this.h = fm.getHeight(); + if (this.h > h) this.h = h; + //this.w = fm.stringWidth("Author: " + c.getText()); + fr = fract; + handle = hc; + } + + public void renderInterp(Graphics g, float fract) { return; } + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + /*ZZDrawingJ2D drw = null; + if (ZZDrawing.instance instanceof ZZDrawingJ2D) + drw = (ZZDrawingJ2D)ZZDrawing.instance; + if (drw != null) { + drw.setFIXME(false); + drw.setQuality(g); + }*/ + Color old = g.getColor(); + FontMetrics fm = font.getFontMetrics((int)(1000 * fr)); + g.setFont(font.getFont((int)(1000 * fr))); + Rectangle asd=g.getClipBounds(); + g.setClip(mx-clipborder,my-clipborder,mw+clipborder*2,mh+clipborder*2); + g.setColor(auth_bg); + g.fillRect(mx,my,mw,mh); + g.setColor(old); + /*if (drw != null) { + drw.setFIXME(true); + drw.setQuality(g); + }*/ + if( fm.stringWidth("Author: " + c.getText()) < mw ) + g.drawString("Author: " + c.getText(), mx,my+ascent); + else g.drawString( c.getText(), mx,my+ascent); + g.drawLine(mx, my+mh-1, mx+mw, my+mh-1); + g.setClip(asd); + } + + public Object hit(int x0, int y0) { + if( x0 >= x && y0 >= y && x0 < x+w && y0 < y+h ) + return handle; + return null; + } + } +} + +// vim: set syntax=java : diff --git a/Modules/virtualcommunity/VCView1.java b/Modules/virtualcommunity/VCView1.java new file mode 100644 index 0000000..0905cbd --- /dev/null +++ b/Modules/virtualcommunity/VCView1.java @@ -0,0 +1,377 @@ +/* +VCView1.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen and Tuomas Lukka + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** First (bad) virtualcommunity view. + */ +public class VCView1 extends VirtualCommunity { + public static final String rcsid = "$Id: VCView1.java,v 1.4 2001/02/27 23:49:30 veparkki Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + public void raster( FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed){ + ZZCell hist = null, hilite = null; + if (!nohistory) { + hist = ZZDefaultSpace.findInheritableParam(view, "history"); + if (hist == null) { + hist = view.h("d.2",1).N("d.2"); + hist.setText("history"); + } + hilite = hist.h("d.1", 1, true); + } + accursed=accursed.h(text); + if (!nohistory) { + if (accursed.h("d.1").equals(hist)) { + hilite = accursed; + accursed = ZZCursorReal.get(accursed); + } + if (hilite == null) { + hilite = hist.N("d.1"); + ZZCursorReal.setcursor(hilite, accursed); + } + histobs.init(view, hilite); + hilite = histobs.histpos; + } + Dimension rd = into.getSize(); + int head = rd.height/15; + if (nohistory) head = 0; + Dimension d = new Dimension(rd.width,rd.height-head); + int w = (int)(d.width * right); + int h = (int)(d.height * middleHeight); + int cx = w/2; + int cy = (int)( (d.height - h) / 2); + int vUnit = (int)(cy / 13); + int lw = (int)(d.width * left); + // gapheight=1/13, line=3/13;4*gap+3*lines=1 + + int bc = 0; + + // pointer + ZZCell p = accursed; + // another pointer + ZZCell ptr = p; + // used to hold kahva cells + Hashtable handles = new Hashtable(); + Hashtable flobs = new Hashtable(); + + int fh = d.height; + int fw = (int) (right * d.width); + + Flob centerFlob = null; + + float fr = ((float)d.width) / 100000.0f; + + int magic = 20; + // Draw the history + int div = 1; + if (!nohistory) div = hist.getRankLength("d.1")-1; + if (div > magic) div = magic; + int hw = (d.width/div)-2, sep=2; + if (hw > head*3) { /*sep+=hw-head*3;*/ hw = head*3; } + int hx = d.width-1-hw; + ZZCell it = null; + if (!nohistory) hist.s("d.1"); + int cnt=0; + if (!nohistory) { + while (!it.equals(hilite)) { cnt++; it = it.s("d.1"); } + if (cnt*2+1 > magic) cnt = (magic-1)/2; + cnt++; + while (cnt++ < magic) { + if (it.s("d.1") != null) it = it.s("d.1"); + else break; + } + } + cnt = 0; + centerFlob = new Flob(0, 0, 1, d.width, head, hist) {}; + into.add(centerFlob); + if (!nohistory) + while (!it.equals(hist) && cnt++ < magic) { + ZZCell hit = ZZCursorReal.get(it); + int hy = 0; + if (hilite != null && it.equals(hilite)) hy = 5; + history.makeFlob(into, hit, it, cfr(fr*hw), hx, hy, 1, hw, head). + setParent(centerFlob); + it = it.s("d.1",-1); + hx -= sep+hw; + } + + //------------------------------------------- + // we have different possibilities: + // author cell + // - headcell in the author dim + // + // product cell + // - no author dim + // - head cell in the kahva dim + // + // message cell + // - have author, not the head cell + //------------------------------------------- + + //if ( fr > 1 ) fr = 1; + //if ( fr < 0.7 ) fr = 0.7f; + p("_____________fr = " +fr); + // make the big blob in the middle + centerFlob = center.makeFlob( into, accursed, accursed, cfr(fr*w), + cx, cy+head, 1, w, h , 0.0f, true); + + //------------------------------------------- + // handle the siblings, parent and children + //------------------------------------------- + + p = accursed; + + int cSibl = 0; + + int sY = cy; + int sX = cx; + + // siblings above the center blob + // calculate the room... + int rc = 0;//p.getRankLength(replies_list) -1; + while( ( p = p.s(replies_list, -1) ) != null ){ + rc++; + } + rc--; + + p("got " + rc + " siblings"); + + p = accursed; + + int sroom = (d.height - h)/2; + if( rc > 0 ) + sroom = sroom / rc; + //fr = (float)0.7; + while( ( p = p.s(replies_list, -1) ) != null && + !p.equals( p.h(replies_list, -1)) && ( cSibl < rc ) ) { + sY = sY - sroom+10; + + //sibl.makeFlob( into, p, p, (float)1.0, + // sX, sY, 1, w, 3*vUnit); + blobs.makeFlob( into, p, p, cfr(fr*w), + sX, sY+head, 1, w, sroom - 20, 0.1f); + + cSibl = cSibl + 1; + //fr -= 0.2; + } + + // parent + ZZCell parent = accursed.h(replies_list,-1); + if( !parent.equals(accursed)){ + int qx = sX-w/2 +2, qy = 5+head, qw = w/2-10, qh = sroom-20; + parent = parent.s(replies, -1); + sibl.makeFlob( into, parent, parent, cfr(fr*(w/2-10)), + qx + qw/2, qy + qh/2, 1, qw , qh, + -0.1f); + parent = parent.h(replies_list, -1, true); + if (parent != null) { + parent = parent.s(replies, -1); + sibl.makeFlob( into, parent, parent, cfr(fr*(w/2-10)), + qx - qw/4, qy - qh/4, 1, qw , qh, + 0.07f); + } + /*into.add(new LineDecor(cx,cy+h/2,sX-w/2+2+(w/2-10)/2, + 5+sroom-20,linecol,2));*/ + } + + p = accursed; + cSibl = 0; + + sY = cy + h + vUnit; + + rc = 0; + while( ( p = p.s(replies_list,1) ) != null ){ + rc++; + } + + p("got " + rc + " siblings"); + + sroom = (d.height - h)/2 - 6; + if( rc > 0 ) + sroom = sroom / rc; + + p = accursed; + + //fr = 0.7f; + + // child + ZZCell child = accursed.h(replies,1); + if( child != accursed ){ + int qx = sX+w+10, qy = sY+head, qw = w/2, qh = d.height-5-sY; + child = child.s(replies_list, 1); + if( child != null) { + ZZCell child2 = child.s(replies_list, 1); + if (child2 != null) { + sibl.makeFlob( into, child2, child2, cfr(fr*(w/2)), + qx+qw/8, qy-qh/2, 1, qw, qh); + } + sibl.makeFlob( into, child, child, cfr(fr*(w/2)), + qx, /*d.height - 3*vUnit-5*/ + qy-qh, 1, qw, qh/*3*vUnit*/); + } + //into.add(new LineDecor(cx+w/2,cy+h,sX+w+10,middle,linecol,2)); + } + + // siblings below the center blob + while( (p = p.s(replies_list, 1) ) != null && (cSibl < rc) ) { + blobs.makeFlob( into, p, p, cfr(fr*w), + sX, sY+10+head, 1, w, sroom-20); + cSibl = cSibl + 1; + sY = sY + sroom; + } + + int th = 0; + + //------------------------------------------- + // handle the other blobs + // depending on the center blob type + //------------------------------------------- + + //------------------------------------------- + // put all the handles to right side + // in every case + //------------------------------------------- + + // loop through the text cells, puts handle cells + // to handles + // XXX loop + p = accursed; + while( (p = p.s(text,1) ) != null){ + ptr = p.h(handle); + if( p.getRankLength(handle) > 1 ) { + handles.put( ""+bc, ptr); + bc++; + } + } + + if ( bc != 0 ) + fh= d.height / bc; + + // blobs on the right side + for( int i = 0; i < bc; i++ ){ + ptr = (ZZCell)handles.get(""+i); + p("th = " + th + " ptr " + ptr); + p("fw = " +fw ); + flobs.put(ptr, blobs.makeFlob( into, ptr, ptr, cfr(fr*(fw-2*xpad)), + d.width - fw-xpad, th+ypad+head, 1, + fw-2*xpad, fh-2*ypad)); + th += fh; + } + + //------------------------------------------- + // draw the links. + // not correct, but SFW, this is just a demo + //------------------------------------------- + for( int i = 0; i< bc; i++ ){ + Flob flo=(Flob)flobs.get(handles.get(""+i)); + Point pq = flo.getPoint(-1,0); + p("flo: " + flo + "p: " + pq); + Point pc = centerFlob.getPoint(1,0); + Flob l = new LinkFlob(pc.x,pc.y,pq.x,pq.y-flo.h/5,pq.x,pq.y+flo.h/5); + into.add(l); + } + + bc=0; + + //------------------------------------------- + // Depending the cell type, put the blobs + // on the left + //------------------------------------------- + + bc = 0; + handles = new Hashtable(); + p=accursed.h(author,-1); + + // author ? + if( accursed == p && p.getRankLength(author) > 1 ){ + p("AUTHOR DUDE"); + // XXX loop + while( (p = p.s(author,1) ) != null){ + //ptr = p.h(text, -1); + p("message"); + //if( p.getRankLength(handle) > 1 ) { + handles.put( ""+bc, p); + bc++; + } + + } else if ( accursed == (p=accursed.h(handle,-1)) && + p.getRankLength(handle) > 1){ + p("PRODUCT"); + // XXX loop + while( (p = p.s(handle,1) ) != null){ + ptr = p.h(text, -1); + //p("message"); + //if( p.getRankLength(handle) > 1 ) { + handles.put( ""+bc, ptr); + bc++; + } + + } + + p("BC = " + bc); + + th = 0; + if ( bc != 0 ) + fh= d.height / bc; + + // blobs on the right side + for( int i = 0; i < bc; i++ ){ + ptr = (ZZCell)handles.get(""+i); + p("flob message"); + p("th = " + th + " ptr " + ptr); + flobs.put(ptr,blobs.makeFlob( into, ptr, ptr, cfr(fr*(w-2*xpad)), + d.width-w-xpad, th+ypad+head, 1, + w-2*xpad, fh-2*ypad)); + th += fh; + } + + //------------------------------------------- + // draw the links. + // not correct, but SFW, this is just a demo + //------------------------------------------- + for( int i = 0; i< bc; i++ ){ + Flob flo=(Flob)flobs.get(handles.get(""+i)); + Point pq = flo.getPoint(-1,0); + p("flo: " + flo + "p: " + pq); + Point pc = centerFlob.getPoint(1,0); + Flob l = new LinkFlob(pc.x,pc.y,pq.x,pq.y-flo.h/5,pq.x,pq.y+flo.h/5); + into.add(l); + } + /* + // draw the links + FlobDecorator linker = new VCLinker(); + linker.decorate(into, "", view); + */ + + + + } + + +} diff --git a/Modules/virtualcommunity/VCView2.java b/Modules/virtualcommunity/VCView2.java new file mode 100644 index 0000000..2afe08d --- /dev/null +++ b/Modules/virtualcommunity/VCView2.java @@ -0,0 +1,263 @@ +/* +VCView2.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka and Vesa Parkkinen + */ + + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** Second, cardstack-like virtualcommunity view. + */ + +public class VCView2 extends VirtualCommunity { + public static final String rcsid = "$Id: VCView2.java,v 1.20 2001/02/28 10:18:20 tjl Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + public void childSeries( FlobSet into, ZZCell cur, int x, int y, + int w, float fract, int orot, int dir, int depth) { + ZZCell s; + + if(cur.s(replies) != null) { + s = cur.s(replies).s(replies_list); + if(s != null) + siblingSeries(into, s, x, y, + w, fract*magfract, orot, 1, depth+1); + } + } + + static int borderLimit = 10; + + final int rotinc = 1; + final int SCOFFS = 10; + + double[]sins = new double[SCOFFS * 2]; + double[]coss = new double[SCOFFS * 2]; + + // Point mkp( + + void addVert(Point p, double h, int rot) { + p("Addvert: "+p+" "+h+" "+rot); + p.x -= (int)(sins[rot+SCOFFS] * h); + p.y += (int)(coss[rot+SCOFFS] * h); + p("Ret: "+p); + } + + + void addHoriz(Point p, double w, int rot) { + p.x += (int)(coss[rot+SCOFFS] * w); + p.y += (int)(sins[rot+SCOFFS] * w); + } + + int getWid(int w, float fract) { + return (int)(w * Math.sqrt(fract)); + } + + int overlap = 10; + int bend = -5; + + public void siblingSeries( FlobSet into, ZZCell cur, int x, int y, + int w, + float fract, int orot, int dir, int depth) { + if(depth >= view2depth) return; + Dimension rd = into.getSize(); + ZZCell s; + int rot = 0;//orot; + + Point curpoint = new Point(x,y); + + Point upstart, downstart; + + Point tmp = new Point(); + + // We do things differently depending on where we are. + // If going to positive direction, first see if we have odd + // or even number of cells and either put a cell in the middle + // or not + + boolean domiddle = true; + + if(dir == 1) { + cur = cur.h(replies_list); + int count = cur.getRankLength(replies_list) - 1; + if(count % 2 == 0) { + domiddle = false; + } + // Either upper or middle + cur = cur.s(replies_list, (count+1)/2); + } + + int cw = getWid(w,fract); + + if(domiddle) { + int h = sibl.getHeight(cur, cfr(fract), cw); + // h /= depth+1; + // h = (int)(80*fract); + + // If not parent, put children for this center blob + if(dir >= 0) { + Point px = new Point(curpoint); + addHoriz(px, cw, rot); + childSeries(into, cur, + px.x, px.y, + w, fract, orot, 1, depth); + } + + addVert(curpoint, -h/2, rot); + sibl.makeFlob(into, cur, cur, cfr(fract), + curpoint.x, curpoint.y, 10, cw, h, + rotunit * orot, + (dir == 0)); + + upstart = new Point(curpoint); + downstart = new Point(curpoint); + addVert(downstart, h, rot); + + } else { + upstart = new Point(curpoint); + downstart = new Point(curpoint); + } + + float cf = fract; + + s=cur; + + if(domiddle) s = s.s(replies_list, -1); + for(; s != null; s = s.s(replies_list, -1)) { + + // if(cy <= borderLimit) break; + // Don't do relcell + if(s.s(replies_list, -1) == null) break; + cf *= magfract; + rot -= rotinc; + cw = getWid(w,cf); + + int ch = sibl.getHeight(s, cfr(cf), cw); + // ch /= depth+1; + // ch = (int)(80*cf); + addVert(upstart, -ch + overlap, rot); + addHoriz(upstart, bend, rot); + sibl.makeFlob(into, s, s, cfr(cf), + upstart.x, upstart.y, + 10, cw, ch, + rotunit * rot, + false); + tmp.setLocation(upstart); + addVert(tmp, ch/2, rot); + addHoriz(tmp, cw, rot); + childSeries(into, s, + tmp.x, tmp.y, + w, cf, rot, 1, depth); + } + + cf = fract; + + s=cur; + rot = orot; + while((s = s.s(replies_list, +1))!=null) { + // if(cy >= rd.height-borderLimit) break; + cf *= magfract; + rot += rotinc; + cw = getWid(w,cf); + + addHoriz(downstart, bend, rot); + addVert(downstart, - overlap, rot); + + int ch = sibl.getHeight(s, cfr(cf), cw); + // ch = (int)(80*cf); + // ch /= depth+1; + sibl.makeFlob(into, s, s, cfr(cf), + downstart.x, downstart.y, + 10, cw, ch, + rotunit * rot, + false); + tmp.setLocation(downstart); + addVert(tmp, ch/2, rot); + addHoriz(tmp, cw, rot); + + childSeries(into, s, + tmp.x, tmp.y, + w, cf, rot, 1, depth); + addVert(downstart, ch, rot); + } + + + // Parents + s = cur.h(replies_list).s(replies, -1); + if(dir <= 0 && s != null) + siblingSeries( + into, s, x - getWid(w, fract*magfract), + y, w, (float)(fract * magfract), + orot, -1, depth+1); + + + + + + + + } + + public void raster( FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed){ + accursed=accursed.h(text); + + Dimension rd = into.getSize(); + Dimension d = rd; + Dimension dprod = new Dimension(rd.width,70); + // Current rotation + double rot = 0; + + { + for(int i=0; i= 2) return; + ZZCell s; + + int upstartx, upstarty, downstartx, downstarty; + + // We do things differently depending on where we are. + // If going to positive direction, first see if we have odd + // or even number of cells and either put a cell in the middle + // or not + + boolean domiddle = true; + int count = 0; + if(dir == 1) { + count = cur.getRankLength(replies_list) - 1; + if(count % 2 == 0) { + domiddle = false; + } + // Either upper or middle + cur = cur.s(replies_list, count/2); + } + + int cw = (int)(w*fract); + + if(domiddle) { + + int h = sibl.getHeight(cur, cfr(fract), cw); + h /= depth+1; + // h = (int)(80*fract); + + sibl.makeFlob(into, cur, cur, cfr(fract), x, y-h/2, 1, cw, h, orot, + (dir == 0)); + + + // If not parent, put children for this center blob + if(dir >= 0) + childSeries(into, cur, x, y, w, fract, orot, 1, depth); + + upstartx = x; + upstarty = y - h/2; + + downstartx = x; + downstarty = y + h/2; + } else { + upstartx = x; + upstarty = y; + + downstartx = x; + downstarty = y; + } + + int cx = upstartx; + int cy = upstarty; + float cf = fract; + + s=cur; + //if(!domiddle) + // s = s.s(replies_list, 1); + double rot = orot; + rot = 0.0; + + + //--- + cx = downstartx; + cy = downstarty; + cf = fract; + + s=cur; + rot = orot; + + + count = cur.getRankLength(replies_list) - 1; + if( count > 0){ + FlobInfo[] fi = new FlobInfo[count]; + int flth=0; + pa("COUNT: " + count); + while((s = s.s(replies_list, +1))!=null ) { + cf *= magfract; + rot += 0.00; + cw = (int)(w*cf); + + int ch = sibl.getHeight(s, cfr(cf), cw); + // ch = (int)(80*cf); + ch /= depth+1; + fi[flth] = new FlobInfo(s,s,cfr(cf), cx,cy,1,cw,ch,rot); + pa("flth: " + flth); + //sibl.makeFlob(into, s, s, cfr(cf), cx, cy, 1, cw, ch, rot, + // false); + childSeries(into, s, cx, cy, w, fract, rot, 1, depth); + //cy += dy; + flth++; + } + + for( int i=1; i<= flth;i++){ + pa("i = " + i); + int mc = 4; + fi[flth-i].y += (flth-i)*(dy) + mc ; + fi[flth-i].x += (flth-i+1)*dx; + fi[flth-i].render(sibl,into); + } + } + cx = upstartx; + cy = upstarty; + cf = fract; + + s=cur; + rot = orot; + + + while(s != null && (s = s.s(replies_list, -1))!=null) { + // Don't do relcell + if(s.s(replies_list, -1) == null) break; + cf *= magfract; + rot = 0.00; + cw = (int)(w*cf); + + int ch = sibl.getHeight(s, cfr(cf), cw); + ch /= depth+1; + // ch = (int)(80*cf); + cy -= dy; + cx -= dx; + sibl.makeFlob(into, s, s, cfr(cf), cx, cy, 1, cw, ch, rot, + false); + childSeries(into, s, cx, cy, w, fract, rot, 1, depth); + } + + //-- + // Parents + s = cur.h(replies_list).s(replies, -1); + if(dir <= 0 && s != null) + siblingSeries( + into, s, x - (int)(w*fract*magfract), + y, w, (float)(fract * magfract), + orot, -1, depth+1); + } + + //} + + class FlobInfo { + int x; + int y; + int h; + int w; + int d; + ZZCell c; + ZZCell hc; + float fr; + double rot; + FlobInfo(ZZCell c, ZZCell hc, float fr, + int x, int y, int d, int w, int h, double rot){ + this.c = c; + this.h=h; + this.fr=fr; + this.x=x; + this.y=y; + this.d=d; + this.w=w; + this.hc=hc; + this.rot = rot; + } + void render(MessageFlobFactory mess, FlobSet into){ + mess.makeFlob(into, c, hc, fr, x, y, d, w, h, rot, + false); + } + + } + + + public void raster( FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed){ + accursed=accursed.h(text); + Dimension rd = into.getSize(); + Dimension d = rd; + + // Current rotation + double rot = 0; + + siblingSeries(into, accursed, 3*d.width/10, d.height/2, 2*d.width/5, + (float)1.0, 0, 0, 0); + + + } +} + + diff --git a/Modules/virtualcommunity/VCView4.java b/Modules/virtualcommunity/VCView4.java new file mode 100644 index 0000000..3901c2a --- /dev/null +++ b/Modules/virtualcommunity/VCView4.java @@ -0,0 +1,141 @@ +/* +VCView4.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ + + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** Second, cardstack-like virtualcommunity view. + */ + + +public class VCView4 extends VirtualCommunity { + public static final String rcsid = "$Id: VCView4.java,v 1.8 2001/02/28 10:18:20 tjl Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + int xstep = 40; + int ystep = 40; + + void mksideFlobs(FlobSet into, ZZCell cur, int x, int y, int w, int h, int d) { + cur = cur.s(replies); + if(cur == null) return; + y += 2*h/3; + h -= 2*h/3; + while((cur = cur.s(replies_list)) != null) { + if(into.findFlob(null, cur) != null) + return; + sibl.makeFlob(into, cur, cur, 0.5f, + x+w, y, d, w/3, h, 0, false); + y -= h/2; + h /= 2; + if(h == 0) return; + } + } + + Point singleSiblingSide(FlobSet into, ZZCell outside, int x, int y, + int w, float fract, int dir, int depth, int side) { + ZZCell cur = outside; + for(int i=1; (cur=cur.s(replies_list,side))!=null; i++) { + if(cur.s(replies_list, -1) == null) break; + float mult = fract / i; + x -= side * mult * xstep; + y += side * mult * ystep; + int h = sibl.getHeight(cur, cfr(fract), w); + sibl.makeFlob(into, cur, cur, cfr(fract), + x, y, 1+50*depth + 2*i, w, h, + 0, false); + mksideFlobs(into, cur, x, y, w+1, h, 1+50*depth); + } + return new Point(x,y); + } + + public void siblingSeries( FlobSet into, ZZCell cur, int x, int y, + int w, + float fract, int dir, int depth) { + // dept + int h = sibl.getHeight(cur, cfr(fract), w); + p("Sibser: "+cur+" "+h+" "+w+" "+x+" "+y); + sibl.makeFlob(into, cur, cur, cfr(fract), + x, y, 1+50*depth, w+1,h, + 0, (depth <= 2)); + if(depth > 2) + mksideFlobs(into, cur, x, y, w+1, h, 1+50*depth); + Point p0 = singleSiblingSide(into, cur, x, y, w, fract, dir, depth, 1); + Point p1 = singleSiblingSide(into, cur, x, y, w, fract, dir, depth, -1); + into.add(new LineDecor(p0.x, p0.y, p1.x, p1.y, Color.red, 1)); + } + + + public void raster( FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed){ + accursed=accursed.h(text); + Dimension rd = into.getSize(); + Dimension dprod = new Dimension(rd.width,70); + Dimension d = rd; + + ZZCell cur = accursed; + + int x = d.width / 3; + int y = d.height / 3; + int w = d.width / 3; + float fr = 1.3f; + + ZZCell child = accursed.s(replies, 1); + + if(child != null) { + child = child.s(replies_list, 1); + siblingSeries(into, child, 2 * d.width / 3, d.height / 2, w, + (float)(fr * 1.0), 0, 1); + } + + for(int pd = 0; pd<4 && cur != null; pd++) { + siblingSeries(into, cur, x, y, w, + fr, 0, 2 + pd); + cur = cur.h(replies_list).s(replies,-1); + fr *= 0.9; + w *= 0.9; + x -= 70; + y -= 70; + } + + if(isProd(accursed)){ + messagesFromProd(into,accursed,(float)1.0); + return; + } else if(isAuthor(accursed)){ + messagesFrom(into,accursed,(float)1.0, author); + return; + } + + addAuthor(into,accursed,1.0f); + + drawProducts(into, (float)1.0, dprod); + + } +} + + + diff --git a/Modules/virtualcommunity/VirtualCommunity.zob b/Modules/virtualcommunity/VirtualCommunity.zob new file mode 100644 index 0000000..bcb9353 --- /dev/null +++ b/Modules/virtualcommunity/VirtualCommunity.zob @@ -0,0 +1,444 @@ +/* +VirtualCommunity.zob + * + * Copyright (c) 2001 Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Vesa Parkkinen + */ + +package org.gzigzag.module; +import org.gzigzag.*; +import java.util.*; +import java.awt.*; + +/** A simple cell factory that gives the cells as one-line strings. + * Variable length is possible. + * UGLY: ALL PARAMS HERE. + */ + +public abstract class VirtualCommunity implements FlobView, ZOb { + public static final String rcsid = "$Id: VirtualCommunity.zob,v 1.36 2001/02/28 10:18:20 tjl Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + // some parameters would be needed, propably + STRUCTPARAMS { + Font font + = new Font("SansSerif", Font.PLAIN, 11); + + ZOb ftextlayouter + = new FTextLayouter(); + + double left + = 0.1; + + double middle + = 0.4; + + double right + = 0.3; + + double middleHeight + = 0.5; + + int xpad + = 5; + + int ypad + = 5; + + Color linecol + = Color.white; + + float magfract + = 0.8f; + + float rotunit + = 0.0f; + + int view2depth + = 4; + + float[] view2ctr // 2..2 + = new float[] {0.35f, 0.5f}; + + float view2wid + = 0.22f; + + float view2fract + = 1.4f; + + + } + + + /** Bold and italic derivatives of the font given. + * The first index is the level of the text i.e. + * from paragraph to H1. + */ + Font[][][] bifonts; + FontMetrics[][][] bifontms; + + INITIALIZE { + bifonts = new Font[7][2][2]; + bifontms = new FontMetrics[7][2][2]; + for(int l = 0; l < bifonts.length; l++) { + int size = font.getSize(); + if(l > 0 && l < 5) size += l-1; + if(l == 5) size += 6; + if(l == 6) size += 9; + bifonts[l][1][0] = new Font(font.getName(), + Font.BOLD, size); + bifonts[l][1][1] = new Font(font.getName(), + Font.BOLD | Font.ITALIC, size); + + if(l == 0) { + bifonts[l][0][0] = new Font(font.getName(), 0, size); + bifonts[l][0][1] = new Font(font.getName(), + Font.ITALIC, size); + } else { // All bold for headers + bifonts[l][0][0] = bifonts[l][1][0]; + bifonts[l][0][1] = bifonts[l][1][1]; + } + for(int b = 0; b<2; b++) + for(int i = 0; i<2; i++) + bifontms[l][b][i] = FONTMETRICS(bifonts[l][b][i]); + } + } + + Color linkcolor = Color.red; + Color default_bgcolor = Color.white; + + static String text = "d.text"; + static String handle = "d.kahva"; + static String author = "d.author"; + static String replies = "d.replies"; + static String replies_list = "d.replies-list"; + + static protected class Foobar implements ZZObs { + private void add() { + vc.h("d.cursor-cargo", -1, this). + h("d.cursor-list", -1, this).s("d.cursor", -1, this); + } + public void chg() { + ZZCell targ = ZZCursorReal.get(vc).h(text); + ZZCell hist = ZZDefaultSpace.findInheritableParam(vc,"history"); + if (targ.h("d.1").equals(hist)) { + p("Historical item"); + histpos = targ; + add(); + return; + } + ZZCell it = hist.s("d.1"); + while (!it.equals(histpos) && !ZZCursorReal.get(it).equals(targ)) + it = it.s("d.1"); + if (!it.equals(histpos)) { + histpos = it; + ZZCursorReal.set(vc, histpos); + } else if (!targ.equals(ZZCursorReal.get(histpos))) { + if (histpos.s("d.1") != null) histpos.disconnect("d.1",1); + histpos = histpos.N("d.1"); + ZZCursorReal.setcursor(histpos, targ); + } + add(); + } + public void init(ZZCell _vc, ZZCell hilite) { + if (inited == false || !_vc.equals(vc)) { + vc = _vc; + histpos = hilite; + inited = true; + } + add(); + } + boolean inited = false; + ZZCell vc; + public ZZCell histpos; + } + static protected Foobar histobs = new Foobar(); + + // flobFactories + MessageFlobFactory blobs = new MessageFlobFactory(); + MessageFlobFactory center = new MessageFlobFactory(); + MessageFlobFactory sibl = new MessageFlobFactory(this); + FlobFactory history = new MessageFlobFactory(); + boolean nohistory = true; + + /** Cut fracts into reasonable range. + */ + protected final float cfr(float fr) { + if (fr < 0.7f) return 0.7f; + if (fr > 2.0f) return 1.5f; + return fr; + } + + abstract public void raster( FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed); + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, + String key, Point pt, ZZScene xi) { + if(id.equals("NEW")) { + + } else { + p("Unknown VC module action: "+id); + } + } + public ZOb newZOb(String id) { + if(id.equals("View")) + return new VCView2(); + if(id.equals("View2")) + return new VCView2(); + if(id.equals("View3")) + return new VCView3(); + if(id.equals("View4")) + return new VCView4(); + else + return null; + } + + + }; + + class VCLinker implements FlobDecorator{ + + public void decorate(FlobSet f, String path, ZZCell view) { + + + } + } + + class LinkFlob extends Flob { + int n = 4; + int[] xs = new int[n]; + int[] ys = new int[n]; + + // Color fg = new Color(0xa6dbac); + Color fg = new Color(0x86bbac); + + public LinkFlob(int x, int y, int x1, int y1, int x2, int y2) { + super(x,y,1,x1-x,y2-y1,null); + xs[0] = x; + xs[1] = x1; + xs[2] = x2; + + ys[0] = y; + ys[1] = y1; + ys[2] = y2; + + n = 3; + } + + public LinkFlob(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) { + super(x,y,1,x1-x,y2-y1,null); + xs[0] = x; + xs[1] = x1; + xs[2] = x2; + xs[3] = x3; + + ys[0] = y; + ys[1] = y1; + ys[2] = y2; + ys[3] = y3; + + n = 4; + } + + + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + Color old = g.getColor(); + g.setColor(fg ); + g.fillPolygon(xs, ys, n); + g.setColor(old); + } + + } + + + Hashtable prods; + + class Dfoo{ + int d; + Dfoo(int d){ + this.d = d; + } + } + + /** + * + */ + + void product(ZZCell c, Point p){ + if(c == null ) return; + if( prods == null) prods = new Hashtable(); + // XXX overwrites... + prods.put(c, p); + } + + + public void messagesFromProd(FlobSet into, ZZCell c, float fract){ + messagesFrom(into,c,fract,handle); + + } + + public void messagesFrom(FlobSet into, ZZCell c, float fract, + String dim){ + ZZCell d = c.h(text,-1); + + int xpad = 5; + int ypad = 5; + int y = ypad; + int w = 100; + int h = into.getSize().height; + int x = into.getSize().width - w - xpad; + int l = d.getRankLength(dim) -1; + pa("L = " + l); + + if( l < 1 ) return; + int hd = h/l; + hd -= ypad; + int depth = 1; + Flob flob = sibl.getSFlob().getFlobSet().findFlob(null,c); + Point pnt = flob.getPoint(1,0); + int cx = pnt.x;//into.getSize().width/2; + int cy = pnt.y; + + d = d.s(dim,1); + ZZCell tmp = d; + while(d != null){ + // make flob + tmp = d.h(text,-1); + sibl.makeFlob(into, tmp, tmp, cfr(fract), + x, y, depth, w,hd, + 0, false); + + // draw link + into.add(new LinkFlob(cx,cy, + x,y+ypad, + x,y+hd-ypad)); + + + d = d.s(dim,1); + y+=hd + ypad; + + } + } + + + + boolean isProd(ZZCell c){ + p("isProd: " + c); + c = c.h(text,-1); + if( c == null ) return false; + if( c.h(handle,-1) == c && c.s(handle,1) != null){ + p("TRUE"); + return true; + } + return false; + } + + boolean isAuthor(ZZCell c){ + + if( c.h(author,-1) == c && c.s(author,1) != null ) + return true; + + return false; + } + + + ZZCell getAuthor(ZZCell c){ + ZZCell d = c.h(text,-1); + d = d.h(author,-1); + return d; + } + + + void addAuthor(FlobSet into, ZZCell c, float fract){ + if( isAuthor(c) ) return; + p("add author"); + if( c==null) return; + ZZCell a = getAuthor(c); + if( a == null ) return; + Dimension d = into.getSize(); + int xpad = 5; + int ypad = 5; + int w = d.width / 5; + int h = d.height / 5; + int x = 0+xpad; + int y = d.height - h-ypad; + int depth = 1; + sibl.makeFlob(into,a,a, fract, + x,y,depth,w,h,0,false); + Flob fl = into.findFlob(null, c); + Point p = fl.getPoint(-1,0); + into.add(new LinkFlob(p.x+5, p.y, p.x,p.y, x+w, y,x+w+5,y)); + } + + + + /** + * + */ + public void drawProducts(FlobSet into, float fraction, + Dimension dp){ + // draw products from cells + p("cells"); + if( prods == null || prods.size() < 1 ) return ; + + int nprods = prods.size(); + + int upperH = dp.height; + int w = into.getSize().width; + int ypad = 5; + int y = ypad; + int xpad = 10; + int x = xpad/2; + int wd = w/(nprods); + int d = 1; + int dprod = 1; + if( wd > w/2 ) wd = w/2; + //FlobSet fs = sibl.getFlobSet(); + + wd -= xpad; + + for(Enumeration e = prods.keys(); + e.hasMoreElements();){ + + + ZZCell cell = (ZZCell)e.nextElement(); + Point p = (Point)prods.get(cell); + + //Dimension pd = blobs.getSize(cells[i], fraction); + //if ( pd == null ) continue; + sibl.makeFlob(into, cell, cell, fraction,x,y,d, + wd,upperH, 0, false); + + int center = x+wd/2; + + into.add(new LinkFlob(center+5, upperH, center, upperH, + p.x,p.y,p.x+5,p.y)); + + x += wd + xpad; + } + } +} + +// vim: set syntax=java : diff --git a/Modules/vob/Connection.java b/Modules/vob/Connection.java new file mode 100644 index 0000000..0b703a6 --- /dev/null +++ b/Modules/vob/Connection.java @@ -0,0 +1,47 @@ +/* +Vob.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A connection to draw between two vobs. + * This doesn't need to store the vob coordinates, so the same Connection + * object can actually be used to draw many connections. + */ + +public abstract class Vob extends Renderable { +public static final String rcsid = "$Id: Connection.java,v 1.1 2001/01/20 08:56:19 bfallenstein Exp $"; + + /** Render this connection between the given vobs. + * Default: render nothing. + */ + public void render(Graphics g, Vob v1, int x1, int y1, + Vob v2, int x2, int y2) { + } + + /** Returns an object telling what was hit. + * Default implementation: returns null. + * XXX interaction with coords? + */ + public Object hit(Vob v1, Vob v2) { return null; } +} diff --git a/Modules/vob/View.java b/Modules/vob/View.java new file mode 100644 index 0000000..330c150 --- /dev/null +++ b/Modules/vob/View.java @@ -0,0 +1,38 @@ +/* +FlobRaster.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; + +/** A fairly general interface for drawing a structure + * on the screen using vobs. + * The parameters have been read through the ZOb interface so + * we don't need to worry about those here. + */ + +public abstract class View { +String rcsid = "$Id: View.java,v 1.1 2001/01/20 08:56:19 bfallenstein Exp $"; + /** Draw a representation of the structure into the VobSet. + */ + public abstract void raster(VobSet into, ZZCell what, CellView cv, + ZZCell win, String[] dims, ZZCell accursed); +} \ No newline at end of file diff --git a/Modules/vob/Vob.java b/Modules/vob/Vob.java new file mode 100644 index 0000000..c32c4d1 --- /dev/null +++ b/Modules/vob/Vob.java @@ -0,0 +1,142 @@ +/* +Vob.java + * + * Copyright (c) 2000, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuomas Lukka + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A vob or visual object shown on the screen. + * Vobs are constant read-only objects like Strings. + *

    + * Vobs should be able to render themselves quickly for animations; + * caching relevant information in this structure is therefore a good idea. + *

    + * The minimal vob implementation simply implements the + * render(Graphics, int, int, int, int, int) method. + */ + +public abstract class Vob extends Renderable { +public static final String rcsid = "$Id: Vob.java,v 1.1 2001/01/20 08:56:19 bfallenstein Exp $"; + + public int w, h; + + /** The cell associated with this vob. + * This may be set to null for things that are - well - just + * things rendered. But those should be in a minority always. + */ + public ZZCell c; + + /** The vob we are interpolating with. + * Storing it here is a pure speed hack: in reality it'd belong in + * a hashtable somewhere. But this is crucial for the frame rate. + */ + protected Vob interpTo; + + /** A 3-tuple with the global coordinates for this vob. + * Conceptually this belongs in the VobStore, but I can't think of a + * clean, not too wasteful implementation. + */ + protected int[] coords; + + /** The lowest-level VobSet this was placed into. + */ + public VobSet vobset; + + public Vob(ZZCell c) { + this.c = c; + } + + /** Get the visual center of this vob. + */ + public Point getCenter(Point p) { + p.x = w/2; p.y = h/2; + return p; + } + + /** Get the visual center of this vob. + */ + public Point getCenter() { + return getCenter(new Point()); + } + + /** Render this vob at the given coordinates. + * Default: render nothing. + * You may override either this function or one or both of + * render(Graphics, int, int) and renderInterp(Graphics, int, int, + int, int, float). + */ + public void render(Graphics g, int mx, int my, int md, + int mw, int mh) { + } + + /** Render this vob. + * May be overridden; default implementation uses render(g, x, y, w, h, d); + */ + public void render(Graphics g, x, y, d) { + render(g, x, y, d, w, h); + } + /** Render an interpolated version of this vob. + * Default implementation uses render(g, x, y, d, w, h) with linearly + * interpolated coordinates. + */ + public void renderInterp(Graphics g, float fract) { + Vob r = interpTo; + if(r==null) return; + render(g, + (int)(x + fract*(r.x-x)), + (int)(y + fract*(r.y-y)), + (int)(d + fract*(r.d-d)), + (int)(w + fract*(r.w-w)), + (int)(h + fract*(r.h-h)) + ); + } + + /** Whether it would make visually sense to interpolate + * this vob. + * Default implementation: whether the sum of the squares of + * the differences of the coordinates and widths is more than 100. + * Not a terribly useful measure but good enough. + */ + public boolean isInterpUseful() { + Vob r = interpTo; + if(r==null) return false; + return (r.x - x) * (r.x - x) + + (r.y - y) * (r.y - y) + + (r.w - w) * (r.w - w) + + (r.h - h) * (r.h - h) > 100; + } + + + /** Returns an object telling what was hit. + * Default implementation: returns null. + */ + public Object hit(int x, int y) { return null; } + + /** A convenience routine to check whether a point + * is inside the defining rectangle. + * If the vob is (as many are) rectangular, this routine can + * be used to check the hit. + */ + public final boolean insideRect(int x0, int y0) { + return x0 >= x && y0 >= y && x0 < x+w && y0 < y+h; + } +} diff --git a/Modules/vob/VobSet.java b/Modules/vob/VobSet.java new file mode 100644 index 0000000..c58e7ea --- /dev/null +++ b/Modules/vob/VobSet.java @@ -0,0 +1,66 @@ +/* +VobSet.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A VobSet. + * This extends Vob in order to get interpolated. XXX is this right? + */ + +public class VobSet extends Vob { +public static final String rcsid = "$Id: VobSet.java,v 1.1 2001/01/20 08:56:19 bfallenstein Exp $"; + + public static final boolean dbg = true; + private static final void p(String s) { if(dbg) System.out.println(s); } + private static final void pa(String s) { System.out.println(s); } + + public VobStore store; + + public ZZCell applitude; + public static ZZCell getApplitude(Vob vob) { return null; } + + public void add(Vob vob, int vx, int vy, int vd) { + store.add(vob, vx+x, vy+y, vd+d, this); + } + + public void add(Connection c, Vob from, Vob to) { + store.add(c, from, to, this); + } + + /** Add a vob as a connection, i.e. in the middle between two other vobs. + * XXX how? + */ + public void add(Vob vob, Vob from, Vob to) { + } + + public void add(Decoration d) { + store.add(d); + } + + public int getX(Vob v) { return v.x - x; } + public int getY(Vob v) { return v.y - y; } + public int getD(Vob v) { return v.d - d; } + public int[] getCoords(Vob v) { return new int[] { v.x-x, v.y-y, v.d-d }; } + +} \ No newline at end of file diff --git a/Modules/vob/VobStore.java b/Modules/vob/VobStore.java new file mode 100644 index 0000000..1f5d7b9 --- /dev/null +++ b/Modules/vob/VobStore.java @@ -0,0 +1,64 @@ +/* +VobStore.java + * + * Copyright (c) 2001, Ted Nelson and Tuomas Lukka + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A store for Vobs. + */ + +public class VobStore implements ZZScene { +public static final String rcsid = "$Id: VobStore.java,v 1.1 2001/01/20 08:56:19 bfallenstein Exp $"; + + public static final boolean dbg = true; + private static final void p(String s) { if(dbg) System.out.println(s); } + private static final void pa(String s) { System.out.println(s); } + + public boolean interpConns = false; + + /** Visual objects. + */ + private int nvobs; + private Vob[] vobs = new Vob[30]; + boolean vsorted = false; + boolean vtagged = false; + + /** Connections between vobs. + * These are rendered before (under) the vobs of the same depth. Note + * that they are interpolated if the interpConns flag is set. + */ + private int nconns; + private Connection[] conns = new Connection[30]; + boolean csorted = false; + + /** Decorations. + * These are always rendered last (above everything else). They are never + * interpolated. + */ + private int ndecors; + private Decoration[] decors = new Decoration[2]; + + // ??? private int maxdepth = 0; + +} + diff --git a/Modules/wordnet/conv.pl b/Modules/wordnet/conv.pl new file mode 100644 index 0000000..5f41174 --- /dev/null +++ b/Modules/wordnet/conv.pl @@ -0,0 +1,160 @@ +# A script to convert wordnet files to ZZ. +# Uses Lingua::Wordnet from CPAN. + +$N = 10000; +$NLETT = 3; + +use Lingua::Wordnet; + +$wn = new Lingua::Wordnet; + + +for my $k (keys %{$wn->{indexhash}}) { + print $k,"\n" if ++$n % 1000 == 0; + last if $n > $N; + local $_ = $k; + s/\%.*//; + # Only nouns. + @synsets = $wn->lookup_synset($_, "n"); + next if !@synsets; + push @words, $_; +} + +@words = sort @words; + +$id = 1; +$txt = ""; +$conns = ""; +$pref = ""; + +$hiercon = ""; +@hier = (); + +$conns .=qq{}; +# Cells for all words. +print "WORDS\n"; +undef $prev; +for(@words) { + my $prevhier; + if($pref ne substr $_, 0, $NLETT) { + for my $i (1..$NLETT) { + my $sub = substr($_, 0, $i); + if(substr($pref, 0, $i) ne $sub) { + $sub = qxml($sub); + $txt .= + qq{$sub\n}; + if(defined $hier[$i]) { + $conns .= qq{ + }; + } + $hier[$i] = $id; + if(defined $prevhier) { + $hiercon .= qq{ + }; + } + $prevhier = $id; + $id++; + } + } + $pref = substr $_, 0, $NLETT; + } + my $t = qxml($_); + $txt .= qq{$t\n}; + $conns .= qq{\n} if defined $prev; + if(defined $prevhier) { + $hiercon .= qq{ + \n}; + } + $prev = $id; + $words{$_} = $id++; +} +$conns .= qq{}; + +$conns .= qq{ $hiercon }; + +# Look for synsets. +print "SYNSETS\n"; +$conns .=qq{}; +for my $w (@words) { + @synsets = $wn->lookup_synset($w, "n"); + $prev = $words{$w}; + for my $synset (@synsets) { + my $offs = $synset->offset(); + if(!exists $synsets{$offs}) { + $gloss = qxml($synset->gloss()); + $txt .= qq{$gloss\n}; + $synsets{$offs} = $id++; + } + $txt .= qq{\n}; + $conns .= qq{\n}; + $prev = $id; + $ssw{$offs."%".$w} = $id++; + } +} +$conns .= qq{}; + +# Connect words inside synset. +print "WORDS IN SYNSETS\n"; +$conns .=qq{}; +for my $k (keys %synsets) { + $synset = $wn->lookup_synset_offset($k); + my @w = $synset->words(); + $prev = $synsets{$k}; + for my $w (@w) { + $w =~ s/\%.*//; + next unless exists $words{$w}; + $c = $ssw{$k."%".$w}; + die "NO SSW '$k' '$w'" unless defined $c; + $conns .= qq{\n}; + $prev = $c; + } +} +$conns .= qq{}; +undef %ssw; +undef @words; +undef %words; + +# Hypo- and hypernyms. +print "HYPO\n"; +$conns .=qq{}; +for my $k (keys %synsets) { + @hypos = $wn->lookup_synset_offset($k)->hyponyms(); + $prev = $synsets{$k}; + for my $h (@hypos) { + my $offs = $h->offset(); + next unless exists $synsets{$offs}; + $txt .= qq{\n}; + $conns .= qq{\n}; + $prev = $id; + $hyp{$offs."%".$k} = $id++; + } +} +$conns .= qq{}; + +print "HYPER\n"; +$conns .=qq{}; +for my $k (keys %synsets) { + @hyper = $wn->lookup_synset_offset($k)->hypernyms(); + $prev = $synsets{$k}; + for my $h (@hyper) { + $lid = $hyp{$k."%".$h->offset()}; + next unless defined $lid; + $conns .= qq{\n}; + $prev = $lid; + } +} +$conns .= qq{}; +undef %hyp; + + +open F, ">out.xml"; +print F qq{ }, $txt, $conns, ""; + +sub qxml { + local $_ = $_[0]; + s/&/&/g; + s//>/g; + s/"/"/g; + return $_; +} diff --git a/Modules/xml/XML.java b/Modules/xml/XML.java new file mode 100644 index 0000000..29779a5 --- /dev/null +++ b/Modules/xml/XML.java @@ -0,0 +1,276 @@ +/* +XML.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Tuukka Hastrup + * Very heavily modified by Tuomas Lukka + */ + +/** An XML importer/exporter. + *

    + * Export:

      + *
    • with data view cursor, point to a cell containing the filename + *
    • running the action XML.EXPORT will now export the whole space + *
    + *

    + * Import:

      + *
    • with data view cursor, point to a cell containing the filename + *
    • if there's a cell from that cell poswards on d.1, this cell + * will be used as a root for the imported space, otherwise a new + * cell is created there + *
    • running the action XML.IMPORT will now import the whole space. + * XXX Notice that if there was a connection from home cell + * negwards on d.1 to be imported, it's not there because that's where + * the filename cell is! + */ + +package org.gzigzag.module; + +import org.gzigzag.*; +import java.io.*; +import java.net.*; +import org.w3c.dom.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; +//import org.openxml.x3p.*; +import org.apache.xml.serialize.*; +import java.util.*; + +import java.awt.Point; + +public class XML { +public static final String rcsid = "$Id: XML.java,v 1.11 2000/11/03 08:01:05 ajk Exp $"; + + public static boolean dbg = true; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public XMLReader getXMLReader() { + return new org.apache.xerces.parsers.SAXParser(); + } + static public Document getDocument() { + return new org.apache.xerces.dom.DOMImplementationImpl(). + createDocument(null, "ZZSpace", null); + } + static public XMLSerializer getXMLSerializer(Writer writ) { + return getXMLSerializer(writ, "UTF-8"); + } + static public XMLSerializer getXMLSerializer(Writer writ, String enc) { + return new org.apache.xml.serialize.XMLSerializer(writ, + new org.apache.xml.serialize.OutputFormat("doc", + enc, true)); + } + + ZZSpace zz; + + static public ZZModule module = new ZZModule() { + public void action(String id, ZZCell code, + ZZCell target, + ZZView v, ZZView cv, + String key, Point pt, + ZZScene xi) { + if(id.equals("EXPORT")) { + synchronized(code.getSpace()) { + (new XML()).export(new File(target.getText()), code.getSpace()); + } + } else if(id.equals("IMPORT")) { + (new XML()).load(new File(target.getText()), target.getOrNewCell("d.1", 1)); + } + } + }; + + AttributesImpl ats(String[] a) { + AttributesImpl ai = new AttributesImpl(); + for(int i=0; i +# +# Description: +# =========== +# +# This is a simple script to port ZigZag (Andrew Pam's perl version) spaces +# to xml. +# +# Usage: +# ===== +# +# First convert zigzag file to ASCII using zzdump from . +# Then convert that file to XML using this script. +# +# zzdump oldfile > somefile +# old2xml.pl < somefile > newfile.xml +# +# +# +# WARNING: +# ======= +# +# This script leaves out all connections and cells that +# have anything to do with d.cursor !!! +# It also adds 1000 to cell ids, just to avoid collision with GZZ cell ids. +# ( This should be changed to something more elegant ) +# +# +############################################################################# + + +$_ = <>; + +#%names; +print qq( + + +); +my $buffer; +while (<>) { + #print "line: $_\n"; + s/ {2,}//; + + if (/'(\d+)'.*/ or /^(\d+).*/) { + + $cellno = $1; + + /.*=>(.*)/; + + $val = $1; + unless ( $val =~ /,/ ) { + $val .= "\n" . <>; + } + $val =~ s/'//g; + # ' + $val =~ s/,//g; + $val =~ s/^ //g; + $val =~ s/ $//g; + + #print "$val\n"; + $names{$cellno} = $val; + } else { + $buffer .= $_; + } + +} + +#while ( ($key, $value) = each %names) { +# print "KEY: $key = VALUE:$value\n"; +#} + +delete $names{0}; + +@lin = split /\n/,$buffer; + +print qq(home\n); + +#@lines = sort @lin; +@lines = @lin; +#print "lines = @lines"; + +foreach (@lines) { + + if (/d\.cursor/) { + goto NEW; + } + if (/'n' => 100/) { + goto NEW; + } + /'(\d+)(.)(.+)'\s+=>\s+(\d+)/; + + $cell = $1; + if ($2 eq "-"){ $dir = -1; } + else { + $dir = 1; + } + + $dim = $3; + $other = $4; + + $cc = $names{$other}; + $cc2 = $names{$cell}; + + $nother = $other + 1000; + $ncell = $cell + 1000; + #print "cc = $cc, cc2 = $cc2\n"; + if ($cc && ! $cc2) { + + print qq($cc\n); + delete $names{$other}; + + } elsif ( $cc2 ) { + + $new_buf .= $_ . "\n"; + + } + else { + $conn_buf .= $_ . "\n"; + } + NEW: +} + +while ($new_buf) { + + + @new_lines = split /\n/,$new_buf; + $new_buf = ""; + @new_lines = sort @new_lines; + #print "NEW_LINES @new_lines /NEWLINES\n"; + + foreach (@new_lines) { + + #print "LINE:$_\n"; + /'(\d+)(.)(.+)'\s+=>\s+(\d+)/; + #print "S1 = $1 S2 = $2 S3 = $3 S4 = $4\n"; + $cell = $1; + if ($2 eq "-"){ $dir = -1; } + else { + $dir = 1; + } + + $dim = $3; + $other = $4; + #print "S1 = $cell S2 = $dir S3 = $dim S4 = $other\n"; + $cc = $names{$other}; + $cc2 = $names{$cell}; + #print "CELLS:cc = $cc, cc2 = $cc2\n"; + $nother = $other + 1000; + $ncell = $cell + 1000; + +# if (! $cc || ! $cc2 ) { +# print "CELLS2:cc = $cc, cc2 = $cc2\n"; +# $new_buf .= $_ . "\n"; +# goto START; +# } + if ($cc && ! $cc2) { + + print qq($cc\n); + delete $names{$other}; + + } elsif ( $cc2 ) { + + $new_buf .= $_ . "\n"; + + } + else { + $conn_buf .= $_ . "\n"; + } + +# +# print qq($cc\n); +# delete $names{$other}; + START: + } +} + +if (! $conn_buf) { + goto END; +} + +@conn_lines = split /\n/,$conn_buf; + +foreach (@conn_lines) { + #print "$_\n"; + /'(\d+)(.)(.+)'\s+=>\s+(\d+)/; + #print "S1 = $1 S2 = $2 S3 = $3 S4 = $4\n"; + $cell = $1; + + if ($2 eq "-"){ $dir = -1; } + + else { + $dir = 1; + } + + $dim = $3; + $other = $4; + + + #print "S1 = $cell S2 = $dir S3 = $dim S4 = $other\n"; + $cc = $names{$other}; + $other = $other + 1000; + $cell = $cell + 1000; + + print qq(\n) +} + +END: +print "\n"; diff --git a/Modules/zaubertrank/README.html b/Modules/zaubertrank/README.html new file mode 100644 index 0000000..0669614 --- /dev/null +++ b/Modules/zaubertrank/README.html @@ -0,0 +1,111 @@ + + + The zaubertrank applitude + + + +

      +The zaubertrank applitude

      + +
      by Benjamin Fallenstein (b.fallenstein@gmx.de)
      + +

      +Name issues

      +The zaubertrank is pronounced TSAU-ber-trunk. The name means "magic potion" +in German. +

      +Raison d'être

      +"Programming for people." As +Chris +Crawford argues in his book +Understanding +Interactivity (2000), computers can expand our capabilities of +thought as much as the written word, but in a different direction: while +writing improved our sequential thinking (thinking in complex chains of +ideas), computers can improve what Chris calls subjunctive thinking (thinking +in many different possibilities). While the book allowed us to bring together +many different ideas, the computer program allows us to explore the countless +permutations resulting from a fixed set of rules. Instead of explaining +the effects of every single possible action to a recipient, we can write +a simulation they can experiment with. +

      Write a simulation? We need to be able to program for that, right? +

      The zaubertrank aims to be what the alphabet was (following Chris' line +of thought) for the Greeks: the very tool that made writing easy to learn, +that was the necessary prerequisite for a culture in which 'everybody' +(every free grown-up male) was supposed to be able to read and write. Before +the alphabet, there were thousands and thousands of signs which one needed +to know by heart in order to produce a written text, or even understand +one. Scribes where a very special class of people who had gotten a lot +of training. The alphabet reduced these signs to a small number which, +once learned, resembled the spoken language. Something people already knew. +

      So what does the zaubertrank do? In a way, the same. The complex world +of signs and abbrevations programming languages consist of is translated +into natural language (albeit not everyday language). Sentences like "Put +the selected card on top of the stack the user clicked on" replace cryptic +formulas like "selected.put(clickStack)," formulas which need time to understand +and more time to actively write. The user doesn't enter these sentences; +that would require a natural language parser far beyond our reach. Rather, +they put it together from fragments functionally equivalent to the tokens +of a programming language: "Put (which card?) on (which stack?)," "the +selected card," and "the stack the user clicked on." This putting together +with menus and mouses also ensures that there can't be any syntax errors: +the computer won't allow the user to enter anything wrong. +

      Will this make computer programming trivial? No, unfortunately not. +Creating a program will still be a complex task needing some thought. But +hopefully, the barriers will be lowered, the learning curve will be better, +and a program won't look as cryptic to non-programmers. +

      +My aim right now

      +In 2001, I will be teaching a course on Interactive Storytelling, which +uses the computer for interactive literary narrative. The interaction here +is not between author and reader or even different authors; rather, it's +between the reader and their computer. Stories take the form of interactive +simulations. Ever read a Choose Your Own Adventure book? Well, if +you imagine a more intelligent behind-the-scenes system than "flip to a +different page," you have the idea of what we'll be dealing with at first. +

      As the people in this course won't be computer science students, I need +some good way to teach them programming easily without wasting too +much time on it. +

      So right now, I'm working on a first version of the zaubertrank, which +shall be suitable for the needs of my course. The goals are: user interaction +in "turns;" relative freedom in the internal workings of the literary simulation; +easy to use for some simple structures, without the need of understanding +the internals right off; an interface showing some text and some possible +reactions (which you can click on). Of course, I need some good editing +tools for the programs, too. +

      I want to realize this as a GZigZag +applitude or zone of functionality. ZigZag(tm) is a new "world" +for computing, designed by +Ted Nelson, +the inventor of computer-based hypertext. It aims to be a replacement for +the file system, for the common user interfaces, for confining structures +like lists, tables, and hierarchies, and for many other things most people +take for granted in their everyday computer use. GZigZag is a free implementation +of the system, lead by Tuomas Lukka at the University of Jyväskylä, +Finland. An applitude is to ZigZag what an application is to the common +computer world, with the difference that applitudes are combinable -- that +is, they live in the same bigger structure and can share parts of their +substructures. One way to look at applitudes is to say they're a way to +interpret a part of the structure. Applitudes can contain custom views, +that is views of the structure which look (somewhat) like the text editors +or other programs we know so well. At the same time, the underlying structure +can be viewed in generic views, which show the "bare metal" in useful ways, +so that it's easy to see how things are stored. +

      Why, you ask, would anyone choose a completely different computer world +they have trouble explaining as the basis for a new system of computer +programming which shall function as the core of a new form of literature +they have even more trouble explaining? Well, because the trouble with +today's programming languages is not only in their cryptic syntax, but +also in the non-visibility of their inner workings. A whole mental model +needs to be build of variables, objects and so on, which can never be shown +on the screen (or only with sophisticated tools written for the classroom). +ZigZag makes this simple. If the underlying design is right, it will be +easy to show what's going on when a program is executed. Besides, once +the ZigZag model is learned, modeling otherwise complex structures in programs +will be easy, because the ZigZag model makes them easy: that's why Tuomas, +the technical leader of the GZigZag project, calls it a "hyperstructure +kit," a toolkit for creating structures beyond lists, tables, and hierarchies. +

      +Components I need

      + + diff --git a/Modules/zaubertrank/TokenTextCellView.java b/Modules/zaubertrank/TokenTextCellView.java new file mode 100644 index 0000000..4985bb8 --- /dev/null +++ b/Modules/zaubertrank/TokenTextCellView.java @@ -0,0 +1,65 @@ +/* +TokenTextCellView.zob + * + * Copyright (c) 2001, Benja Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benja Fallenstein + */ + +package org.gzigzag; +import java.util.*; +import java.awt.*; + +/** A cell view for showing (and editing) the text of a zaubertrank token. + * (This is to be used with ideosyncratic, not as the main cell view for a + * window.) The text for a token is connected to the token poswards on + * d.zt-text. Variables are recognized by them being clones. Their names are + * simply the content of the cloned cell. Thus, clones are shown with a + * different background/foreground; that's all we do to distinguish variables. + */ + +public class TokenTextCellView extends FTextCellView { +public static final String rcsid = "$Id: TokenTextCellView.java,v 1.1 2001/04/01 17:45:17 bfallenstein Exp $"; + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + public static String zttext = "d.zt-text"; + public static Color varbg = Color.darkGray; + public static Color varfg = Color.gray; + + /** Get the FText for this cell at the given scale. + * scale == fract * 1000. + */ + protected FText getFText(ZZCell c0, int scale) { + ZZCell cells[] = c0.readRank(zttext, 1, false); + FText.Part parts[] = new FText.Part[cells.length]; + + for(int i=0; i=0; i--) args[i] = data.pop(); + data.push(p.eval(new Data(args))); + } else if(root.s("d.zt-arg") != null) { + int nr = Data.i(root.s("d.zt-arg")); + data.push(frame.o(nr)); + } else { // FUNCTION CALL! (XXX need argument reads) + throw new ZZError("Function calls aren't working yet!"); +/* + Parser.DecNode dn = new Parser.DecNode(root); + Object[] args = new Object[dn.params.length]; + for(int i=args.length-1; i>=0; i--) args[i] = data.pop(); + returns.push(pos); + frames.push(frame); + frame = new Data(args); + pos = dn.c.h("zaubertrank:rpn"); // XXX fix +*/ + } + pos = pos.s(Parser.sequencedim); + } + + static public Object eval(ZZCell what, Data args) { + Evaluator e = new Evaluator(what, args); + while(e.running()) e.step(); + if(e.failed) return null; + return e.data.pop(); + } + + public boolean running() { + return (!failed && pos != null); + } + + public boolean finished() { + return (!failed && pos == null); + } +} \ No newline at end of file diff --git a/Modules/zaubertrank/old/ParsedView.zob b/Modules/zaubertrank/old/ParsedView.zob new file mode 100644 index 0000000..e1f11d7 --- /dev/null +++ b/Modules/zaubertrank/old/ParsedView.zob @@ -0,0 +1,209 @@ +/* +ParsedView.zob + * + * Copyright (c) 2000, Benjamin Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.zaubertrank; +import org.gzigzag.*; +import java.awt.*; +import java.util.*; + +/** A view for the zaubertrank using the Parser class. + */ + +public class ParsedView implements FlobView, ZOb { + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + + STRUCTPARAMS { + /** The font to use. */ + Font font + = new Font("SansSerif", Font.PLAIN, 16); + + ZOb ftextlayouter + = new FTextLayouter(); + + /** Whether to mark the accursed part. */ + boolean mark + = false; + + int xmargin + = 8; + + int ymargin + = 2; + + int yspace + = 10; + } + + FontMetrics fm; + + INITIALIZE { + fm = FONTMETRICS(font); + } + + static class TokenPart extends FText.CellPart { + int tkNumber; + ZZCell tkHandle; + public TokenPart(ZZCell c, int offs, int n, Font f, FontMetrics fm, + Color bg, Color fg, int tkNumber, ZZCell tkHandle) { + super(c, offs, n, f, fm, bg, fg); + this.tkNumber = tkNumber; + this.tkHandle = tkHandle; + } + public FText.Part subpart(int first, int last) { + return new TokenPart(c, offs+first, last-first, f, this.fm, + bg, fg, tkNumber, tkHandle); + } + public Renderable rend(int x, int y, int d, Renderable prev0) { + TokenFlob prev = null, parent = null, res; + p("SimpleView.TokenPart.rend prev "+prev0); + if(prev0 instanceof TokenFlob) { + prev = (TokenFlob)prev0; + if(prev.c != this.c) prev = null; + else if(prev.parent != null) parent = (TokenFlob)prev.parent; + else parent = prev; + } + p("SimpleView.TokenPart.rend found prev "+prev+" -- parent "+parent); + res = new TokenFlob(x, y, d, width(), height(), + c, s, f, this.fm, parent, offs, n, bg, tkHandle); + if(prev != null) res.setPrev(prev); + if(parent == null) res.tkNumber = tkNumber; + p("SimpleView.TokenPart nr "+tkNumber+" has nr "+res.tkNumber+" rend: "+res); + return res; + } + } + + FText.Part make(ZZCell c, int number, ZZCell tkHandle, + ZZCell view) { + Color bg = null; + if(mark && tkHandle.equals(ZZCursorReal.get(view))) + bg = ZZCursorReal.getColor(view); + Color fg = Color.black; + return new TokenPart(c, 0, -1, font, fm, bg, fg, number, tkHandle); + } + FText.Part make(String s) { + return new FText.StringPart(s, font, fm, null, Color.black); + } + + void getParts(Vector v, Parser.TypeRef tr, TokenGrouper g, int parent, + ZZCell tkHandle, ZZCell view) { + int number = g.addToken(parent); + ZZCell[] text = tr.getText(); + if(text == null) { v.addElement(make("")); return; } + v.addElement(make("[")); + for(int i=0; i= 0) inits[1] = res.y + res.height + 2*ym + yspace + 6; + } + + public void raster(FlobSet into, FlobFactory fact, + ZZCell view, String[] dims, ZZCell accursed) { + ZZCell c = accursed; + while(c.h(Parser.paramdim) != c || + c.h(Parser.valuedim) != c) { + c = c.h(Parser.paramdim); + c = c.h(Parser.valuedim); + } + + TokenGrouper grp = new TokenGrouper(); + Parser.GrammarNode gn = new Parser.GrammarNode( + view.getSpace().getHomeCell().s(Parser.grammardim)); + Parser.ExpNode en = new Parser.ExpNode(c); + Dimension size = into.getSize(); + Rectangle rect = new Rectangle(xmargin, ymargin, size.width-2*xmargin, + size.height-2*ymargin); + + int[] inits = new int[2]; + inits[0] = (inits[1] = rect.y + rect.height/2); + + place(into, en, rect, grp, gn, 0, view, inits); + + for(Parser.ExpNode en0 = en.step(-1); + en0 != null && inits[0] > rect.y; + en0 = en0.step(-1)) { + place(into, en0, rect, grp, gn, -1, view, inits); + } + + for(Parser.ExpNode en1 = en.step(1); + en1 != null && inits[1] < rect.y+rect.height; + en1 = en1.step(1)) { + place(into, en1, rect, grp, gn, 1, view, inits); + } + + grp.group(into); + } +} +// vim: set syntax=java : diff --git a/Modules/zaubertrank/old/Parser.java b/Modules/zaubertrank/old/Parser.java new file mode 100644 index 0000000..b3e4781 --- /dev/null +++ b/Modules/zaubertrank/old/Parser.java @@ -0,0 +1,275 @@ +/* +Parser.java + * + * Copyright (c) 2000, Benjamin Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ + +package org.zaubertrank; +import org.gzigzag.*; +import java.util.*; + +/** A parser for zaubertrank programs. + * Currently micro-level: the biggest structure recognized is one statement. + */ + +public class Parser { +public static final String rcsid = "$Id: Parser.java,v 1.1 2001/04/02 20:29:05 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static Object NULL = new Object(); + + static public final String paramdim = "d.2"; // parameter list dim + static public final String valuedim = "d.1"; + static public final String recorddim = "d.1"; + static public final String sequencedim = "d.zaubertrank-list"; + static public final String textdim = "d.zaubertrank-txt-alt"; + static public final String textrankdim = "d.2"; + static public final String textgrammardim = "d.1"; + static public final String grammardim = "d.zaubertrank-grammar-list"; + static public final String decdim = "d.zaubertrank-declarations"; + + /** A reference to an ExpNode param in a certain grammatical form. */ + static public final class DecRef { + int i; + GrammarNode g; + + public DecRef(int i, GrammarNode g) { this.i = i; this.g = g; } + } + + /** A reference to a certain ExpNode in a certain grammatical form. + * The difference to DecRef is that DecRef contains only a param number + * and a GrammarNode; additionally, an ExpNode is needed to read the + * actual text. + */ + static public final class ExpRef { + ExpNode e; + GrammarNode g; + + public ExpRef(ExpNode e, GrammarNode g) { this.e = e; this.g = g; } + public Object[] getText() { return e.getText(g); } + } + + static public final class TypeRef { + TypeNode t; + GrammarNode g; + + public TypeRef(TypeNode t, GrammarNode g) { this.t = t; this.g = g; } + public ZZCell[] getText() { return t.getText(g); } + } + + static public class Node { + public ZZCell c; + public boolean equals(Node other) { return c.equals(other.c); } + } + + /** A node declaring a grammatical way to utter a type. + * Example: English noun ("the person" // "which person?") + * Example: English statement ("the ball is red" // "what is true?") + * Example: English genitive ("the person's" // "whose?") + * etc. + */ + static public class GrammarNode extends Node { + public GrammarNode(ZZCell c) { + this.c = c.getRootclone(); + if(!this.c.h(grammardim).equals(this.c.getSpace().getHomeCell())) + throw new ZZError("Attempt to create GrammarNode from " + + "non-grammar cell "+this.c); + } + public GrammarNode(ZZSpace sp) { + this.c = sp.getHomeCell().N(grammardim, 1); + } + } + + static ZZCell[] readText(ZZCell c, GrammarNode g) { + ZZCell root = c.intersect(textdim, 1, g.c, "d.clone", 1); + p("Parse intersect "+c+" and "+g.c+" gives "+root); + if(root == null) return null; + return root.readRank(textrankdim, 1, false); + } + static void writeText(ZZCell c, GrammarNode g, ZZCell[] tc) { + ZZCell here = g.c.zzclone(); + c.insert(textdim, 1, here); + for(int i=0; i= params.length || params[i] == null) continue; + if(params[i].c.s(valuedim, -1) != null) + params[i].c.disconnect(valuedim, -1); + here.connect(valuedim, 1, params[i].c); + } + } + + /** Change a param in the structure. */ + public void setParam(int nr, ExpNode val) { + ZZCell var = c.getOrNewCell(paramdim, nr+1); + if(var.s(valuedim) != null) var.disconnect(valuedim, 1); + if(val.c.s(valuedim, -1) != null) val.c.disconnect(valuedim, -1); + var.connect(valuedim, 1, val.c); + } + + /** Read the text for a given GrammarNode. + * Returns an Object[] array where the Objects are ZZCells + * (which contain a piece of the text) ExpRef objects, or TypeRef + * objects. + *
      + * NOTE: there is no corresponding setText function because the + * text is deducted from params[] and dec.getText(). + */ + public Object[] getText(GrammarNode g) { + Object[] res = dec.getText(g); + if(res == null) return null; + for(int i=0; i= 0) { + if(toks[tf.tkNumber] == null) + toks[tf.tkNumber] = tf; + else + tf.setTkFirstPart(toks[tf.tkNumber]); + } + p("...is TokenFlob "+tf.tkNumber); + } + }}, false); + int child = 0; + for(Enumeration e = parents.elements(); e.hasMoreElements();) { + int parent = ((Integer)e.nextElement()).intValue(); + p("TokenGroup connect parent "+parent+" child "+child); + if(parent >= 0 && toks[child] != null && toks[parent] != null) + toks[child].setTkParent(toks[parent]); + child++; + } + } + +} + +// vim: set syntax=java : diff --git a/Modules/zaubertrank/old/Zaubertrank.java b/Modules/zaubertrank/old/Zaubertrank.java new file mode 100644 index 0000000..c0b749c --- /dev/null +++ b/Modules/zaubertrank/old/Zaubertrank.java @@ -0,0 +1,54 @@ +/* +Zaubertrank.java + * + * Copyright (c) 2000, Benjamin Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.gzigzag.module; +import org.gzigzag.*; +import java.awt.*; + +/** The module for the Zaubertrank applitude. + */ + +public class Zaubertrank { +public static final String rcsid = "$Id: Zaubertrank.java,v 1.1 2001/04/02 20:29:05 bfallenstein Exp $"; + public static boolean dbg = false; + static final void p(String s) { if(dbg) System.out.println(s); } + static final void pa(String s) { System.out.println(s); } + + static public ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, Point pt, ZZScene xi) { + Flob[] flob = new Flob[1]; + if(pt != null) ((FlobSet)xi).getObjectAt(pt.x, pt.y, flob); + org.zaubertrank.Actions.action(view.getViewcell(), id, flob[0]); + } + public ZOb newZOb(String id) { + if(id.equals("Simple")) + return new org.zaubertrank.SimpleView(); + else if(id.equals("Parsed")) + return new org.zaubertrank.ParsedView(); + + return null; + } + }; +} diff --git a/Modules/zaubertrank/old/ZaubertrankPart.java b/Modules/zaubertrank/old/ZaubertrankPart.java new file mode 100644 index 0000000..efa5cdb --- /dev/null +++ b/Modules/zaubertrank/old/ZaubertrankPart.java @@ -0,0 +1,216 @@ +/* +ZaubertrankPart.java + * + * Copyright (c) 2000, Benjamin Fallenstein + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Benjamin Fallenstein + */ +package org.zaubertrank; +import org.gzigzag.*; +import java.util.*; + +/** A spacepart for the zaubertrank. + * Currently connects tokens in Reverse Polish Notation, and has cells whose + * content is the computed result of a Zaubertrank function. + */ + +public class ZaubertrankPart extends ZZROSpacePart { +public static final String rcsid = "$Id: ZaubertrankPart.java,v 1.1 2001/04/02 20:29:05 bfallenstein Exp $"; + public static boolean dbg = false; + private static final void p(String s) { if(dbg) System.out.println(s); } + private static final void pa(String s) { System.out.println(s); } + + public ZaubertrankPart(ZZSpace space, String id) { + super(space, id); + } + + public static class Result { + String codeID; + int nr; + public Result(String c, int nr) { codeID = c; this.nr = nr; } + } + + public Object parseIDPart(String idPart) { + if(idPart.substring(0, 7).equals("result-")) { + String rest = idPart.substring(7); + int idx = rest.indexOf("-"); + if(idx < 0 || idx+1 == rest.length()) return null; + String nr = rest.substring(0, idx); + String codeID = rest.substring(idx+1); + try { + return new Result(codeID, Integer.parseInt(nr)); + } catch(NumberFormatException e) { + return null; + } + } else + return null; + } + + public String generateIDPart(Object parsed) { + if(parsed instanceof Result) { + Result r = (Result)parsed; + return "result-" + r.nr + "-" + r.codeID; + } else + throw new ZZError("Not a ZaubertrankPart parsed ID object!"); + } + + public String getText(ZZCellHandle c) { + if(c.parsedID instanceof Result) { + Result r = (Result)c.parsedID; + ZZCell code = space.getCellByID(r.codeID); + pa("code "+code); + Object res; + try { + res = Evaluator.eval(code, new Data(c)); + } catch(Throwable t) { + // ZZLogger.exc(t); + return t.getMessage(); + } + return Data.s(res); + } else + return ""; + } + + public ZZDimension getDim(String name) { + if(name.equals("result")) return new ResultDimension(); + else if(name.equals("rpn")) return new ReversePolishNotation(); + return null; + } + + public class ResultDimension extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + Result r = null; + if(c.parsedID instanceof Result) r = (Result)c.parsedID; + + if(r == null) { + if(steps <= 0) return null; + r = new Result(c.getID(), steps); + return (ZZCellHandle)space.getCellByID(ZaubertrankPart.this, + generateID(r), r); + } else { + r = new Result(r.codeID, r.nr + steps); + if(r.nr < 0) return null; + else if(r.nr == 0) + return (ZZCellHandle)space.getCellByID(r.codeID); + else + return (ZZCellHandle)space.getCellByID(ZaubertrankPart.this, + generateID(r), r); + } + } + } + + public static ZZCell parent(ZZCell c, ZZObs o) throws SyntaxError { + c = c.s(Parser.valuedim, -1, o); + if(c == null) return null; + c = c.h(Parser.paramdim, -1, true, o); + if(c == null) throw new SyntaxError("Not connected to parent!"); + return c; + } + private static ZZCell sibling(ZZCell c, int dir, ZZObs o) + throws SyntaxError { + c = c.s(Parser.valuedim, -1, o); + if(c == null) return null; // XXX syntax error? has no siblings at all! + c = c.s(Parser.paramdim, dir, o); + if(dir < 0 && c == null) throw new SyntaxError("was parent already"); + else if(dir > 0 && c == null) return null; + // i.e., this was the last sibling + else if(dir < 0 && c.s(Parser.paramdim, -1, o) == null) return null; + // i.e., this was the first sibling + c = c.s(Parser.valuedim, 1, o); + if(c == null) throw new MissingTermError("Term's missing"); + return c; + } + public static ZZCell prevSibling(ZZCell c, ZZObs o) throws SyntaxError { + return sibling(c, -1, o); + } + public static ZZCell nextSibling(ZZCell c, ZZObs o) throws SyntaxError { + return sibling(c, 1, o); + } + public static ZZCell firstChild(ZZCell c, ZZObs o) throws SyntaxError { + c = c.s(Parser.paramdim, 1, o); + if(c == null) return null; + c = c.s(Parser.valuedim, 1, o); + if(c == null) throw new MissingTermError("Term's missing"); + return c; + } + public static ZZCell lastChild(ZZCell c, ZZObs o) throws SyntaxError { + c = c.h(Parser.paramdim, 1, true, o); + if(c == null) return null; + c = c.s(Parser.valuedim, 1, o); + if(c == null) throw new MissingTermError("Term's missing"); + return c; + } + + public static ZZCell firstDescendant(ZZCell c, ZZObs o) throws SyntaxError { + LoopDetector l = new LoopDetector(); + ZZCell d = c; + while(true) { + d = firstChild(c, o); + if(d == null) return c; + c = d; + l.detect(c); + } + } + + public static ZZCell rpnPrev(ZZCell c, ZZObs o) throws SyntaxError { + ZZCell d = lastChild(c, o); + if(d != null) return d; + LoopDetector l = new LoopDetector(); + while(true) { + d = prevSibling(c, o); + if(d != null) return d; + l.detect(c); + c = parent(c, o); + if(c == null) return null; + } + } + + public static ZZCell rpnNext(ZZCell c, ZZObs o) throws SyntaxError { + ZZCell d = nextSibling(c, o); + if(d == null) return parent(c, o); + else return firstDescendant(d, o); + } + + public class ReversePolishNotation extends ZZRODimension { + public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) { + // Sanity check: can this be a tree node? + if(c.s(Parser.valuedim, 1, o) != null) return null; + if(c.s(Parser.paramdim, -1, o) != null) return null; + // Until we have syntax error cells, let the errors be throws. + // try { + if(steps > 0) + for(int i=0; isteps; i--) + c = (ZZCellHandle)rpnPrev(c, o); + + // Another sanity check + if(c != null && (c.s(Parser.valuedim, 1, o) != null || + c.s(Parser.paramdim, -1, o) != null)) + throw new SyntaxError("Target not a tree node!"); + + return c; + // } catch(SyntaxError e) { + // ZZLogger.exc(e); + // return null; + // } + } + } +} + diff --git a/Modules/ztp/ZTPclient.java b/Modules/ztp/ZTPclient.java new file mode 100644 index 0000000..627b82f --- /dev/null +++ b/Modules/ztp/ZTPclient.java @@ -0,0 +1,71 @@ +/* +ZTPclient.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.module; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import org.gzigzag.ztp.client.*; +import java.awt.*; +import java.net.*; +import java.io.*; + +public class ZTPclient { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + private static Action[] actions = { new Get(), new Put() }; + + public static ZZModule module = new ZZModule() { + public void action(String id, + ZZCell code, + ZZCell target, + ZZView view, ZZView cview, String key, + Point pt, ZZScene xi) { + for (int i = 0; i < actions.length; i++) { + if (id.toUpperCase().equals(actions[i].name().toUpperCase())) { + RemotePieceData rpd = new RemotePieceData(); + String err = rpd.readParams(target); + if (err != null && !err.equals("")) throw new ZZError(err); + Session ses = null; + if (actions[i].needSession()) { + try { + ses = new Session(rpd.serverFQDN, rpd.serverPort); + ses.login(rpd.userName, rpd.userPassword); + } catch (UnknownHostException e) { + throw new ZZError(""+e); + } catch (IOException e) { + throw new ZZError(""+e); + } + } + actions[i].action(rpd, ses); + try { + if (ses != null) ses.close(); + } catch (IOException e) { + throw new ZZError(""+e); + } + return; + } + } + throw new ZZError("unknown ZTPclient action"); + } + }; + +} diff --git a/Modules/ztp/ZTPserver.java b/Modules/ztp/ZTPserver.java new file mode 100644 index 0000000..d565e8e --- /dev/null +++ b/Modules/ztp/ZTPserver.java @@ -0,0 +1,82 @@ +/* +STPserver.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.module; +import org.gzigzag.ztp.*; +import org.gzigzag.ztp.server.*; +import org.gzigzag.*; +import java.net.*; +import java.io.*; +import java.util.*; + +/** This is a prototype STP server. Currently it supports a + * mock-STP/TCP in order to test the ideas in the WIP spec. */ +public class ZTPserver { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + protected Listener listener; + + public ZTPserver(ZZSpace space, Integer inetport) { + this(space, inetport.intValue()); + } + + public ZTPserver(ZZSpace space, int inetport) { + p("ZTP creation start"); + ServerSocket sock; + try { + sock = new ServerSocket(inetport); + } catch (IOException e) { + throw new ZZError("Unable to bind to server port " + inetport + ": " + e); + } + listener = new Listener(space, sock); + listener.start(); + p("ZTP creation finished"); + } + + public void kill() throws InterruptedException { + listener.interrupt(); + listener.join(); + for (Enumeration e = Session.getActiveSessions(); e.hasMoreElements();) { + Session s = (Session) e.nextElement(); + s.interrupt(); + } + for (Enumeration e = Session.getActiveSessions(); e.hasMoreElements();) { + Session s = (Session) e.nextElement(); + s.join(); + } + } + + public static void main(String[] args) { + ZTPserver serv = new ZTPserver(new ZZDimSpace(), 5555); + try { + serv.listener.join(); + serv.kill(); + } catch (InterruptedException e) { + ZZLogger.exc(e); + } + SafeExit.exit(0); + } + +} + + + diff --git a/Modules/ztp/client/Action.java b/Modules/ztp/client/Action.java new file mode 100644 index 0000000..bf802f0 --- /dev/null +++ b/Modules/ztp/client/Action.java @@ -0,0 +1,29 @@ +/* +Action.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag.ztp.client; + +public interface Action { + String name(); + boolean needSession(); + void action(RemotePieceData rpd, Session ses); +} + diff --git a/Modules/ztp/client/Get.java b/Modules/ztp/client/Get.java new file mode 100644 index 0000000..9bc9095 --- /dev/null +++ b/Modules/ztp/client/Get.java @@ -0,0 +1,43 @@ +/* +Get.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag.ztp.client; +import org.gzigzag.ztp.*; +import org.gzigzag.*; +import java.io.*; +import java.util.*; + +public class Get implements Action { + + public String name() { return "GET"; } + public boolean needSession() { return true; } + public void action(RemotePieceData rpd, Session ses) { + + try { + ses.get(rpd.subspaceName, rpd.subspace); + } catch (IOException e) { + throw new ZZError("" + e); + } + + + + } +} diff --git a/Modules/ztp/client/Put.java b/Modules/ztp/client/Put.java new file mode 100644 index 0000000..dd522dd --- /dev/null +++ b/Modules/ztp/client/Put.java @@ -0,0 +1,43 @@ +/* +Put.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag.ztp.client; +import org.gzigzag.ztp.*; +import org.gzigzag.*; +import java.io.*; +import java.util.*; + +public class Put implements Action { + + public String name() { return "PUT"; } + public boolean needSession() { return true; } + public void action(RemotePieceData rpd, Session ses) { + if (rpd.subspace == null) throw new ZZError("there's nothing to put!"); + Subspace ss = new Subspace(rpd.subspace.s("d.ztp-subspace")); + try { + ses.put(rpd.subspaceName, ss.getCells(), ss.getSoftDims()); + } catch (IOException e) { + throw new ZZError("" + e); + } + } + +} + diff --git a/Modules/ztp/client/RemotePieceData.zob b/Modules/ztp/client/RemotePieceData.zob new file mode 100644 index 0000000..e632d93 --- /dev/null +++ b/Modules/ztp/client/RemotePieceData.zob @@ -0,0 +1,64 @@ +/* +RemotePieceData.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.client; +import org.gzigzag.*; + +public class RemotePieceData implements ZOb { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + STRUCTPARAMS { + + /** Server FQDN. */ + String serverFQDN = null; + + /** Server port. */ + int serverPort = -1; + + /** User name. */ + String userName = null; + + /** User password. */ + String userPassword = null; + + /** Subspace name. */ + String subspaceName = "ALL"; + + /** Subspace handle. */ + ZZCell subspace = null; + + } + + INITIALIZE { + if (serverFQDN == null) throw new ZZError("need server FQDN"); + if (serverPort == -1) throw new ZZError("need server port"); + if (userName == null) throw new ZZError("need a user name"); + if (subspaceName == null) throw new ZZError("need a subspace name"); + p("serverFQDN = " + serverFQDN); + p("serverPort = " + serverPort); + p("userName = " + userName); + p("userPassword = " + userPassword); + p("subspaceName = " + subspaceName); + p("subspace = " + subspace); + } + +} diff --git a/Modules/ztp/client/Response.java b/Modules/ztp/client/Response.java new file mode 100644 index 0000000..d2db63f --- /dev/null +++ b/Modules/ztp/client/Response.java @@ -0,0 +1,76 @@ +/* +Session.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.client; +import org.gzigzag.*; +import org.gzigzag.ztp.*; + +class Response { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + public int major; + public int minor; + public int ident; + + // Major codes + public final static int positivePreliminary = 1; + public final static int positiveCompletion = 2; + public final static int positiveIntermediate = 3; + public final static int transientNegativeCompletion = 4; + public final static int permanentNegativeCompletion = 5; + + // Minor codes + public final static int syntaxCode = 0; + public final static int informationCode = 1; + public final static int connectionCode = 2; + public final static int authenticationCode = 3; + public final static int subspaceCode = 4; + + public String explanation; + + public Response(String line) { + try { + ZTPCommand.RV r; + + r = ZTPCommand.ASCII_number(line); + p("r = " + r); + if (r == null || r.rest.charAt(0) != '.') throw new SyntaxError("bad response line: " + line); + major = Integer.parseInt(r.token); + + r = ZTPCommand.ASCII_number(r.rest.substring(1)); + p("r = " + r); + if (r == null || r.rest.charAt(0) != '.') throw new SyntaxError("bad response line: " + line); + minor = Integer.parseInt(r.token); + + r = ZTPCommand.ASCII_number(r.rest.substring(1)); + p("r = " + r); + if (r == null || r.rest.charAt(0) != ' ') throw new SyntaxError("bad response line: " + line); + ident = Integer.parseInt(r.token); + + r = ZTPCommand.lwsp(r.rest); + explanation = r.rest; + } catch (NumberFormatException e) { + throw new ZZError("" + e); + } + } + +} diff --git a/Modules/ztp/client/Session.java b/Modules/ztp/client/Session.java new file mode 100644 index 0000000..e83cf53 --- /dev/null +++ b/Modules/ztp/client/Session.java @@ -0,0 +1,165 @@ +/* +Session.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.client; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.net.*; +import java.io.*; +import java.util.*; + +public class Session implements SafeExit.Cleanupable { + + private String server; + private Socket sock; + private int port; + private LineBufferedIO io; + + public Session(String server, int port) throws UnknownHostException { + this.server = server; + this.port = port; + + try { + sock = new Socket(server, port); + io = new LineBufferedIO(sock.getInputStream(), sock.getOutputStream()); + + String line = io.readline(); + Response resp = new Response(line); + if (resp.major != Response.positiveCompletion) { + sock.close(); + throw new ZZError("no response from server"); + } + } catch (IOException e) { + throw new ZZError("" + e); + } + SafeExit.registerObject(this); + } + + /** Login to server. If passwd is null, attempt + * preauthentication. */ + public void login(String username, String passwd) throws IOException { + if (passwd == null) { + io.writeln("AUTH/PRE " + ZTPCommand.encode(username)); + } else { + io.writeln("AUTH/PASS " + ZTPCommand.encode(username) + + " " + ZTPCommand.encode(passwd)); + } + Response resp = new Response(io.readline()); + if (resp.major != Response.positiveCompletion) { + throw new ZZError("Unable to login: " + resp.explanation); + } + } + + public void close() throws IOException { + io.writeln("QUIT"); + io.readline(); + sock.close(); + SafeExit.unregisterObject(this); + } + + public void cleanup() throws Throwable { + io.writeln("A"); + io.readline(); + io.writeln("QUIT"); + io.readline(); + sock.close(); + } + + public void put(String subspace, Enumeration cells, String[] sdims) throws IOException { + io.writeln("PUT " + ZTPCommand.encode(subspace)); + Response res = new Response(io.readline()); + if (res.major != Response.positiveIntermediate) { + throw new ZZError("unable to put: " + res.explanation); + } + SubspaceDump.dump(io, cells, sdims, ""); + res = new Response(io.readline()); + if (res.major != Response.positiveCompletion) { + throw new ZZError("failed to put: " + res.explanation); + } + } + + public void get(String subspace, ZZCell basecell) throws IOException { + io.writeln("GET " + ZTPCommand.encode(subspace)); + Response res = new Response(io.readline()); + if (res.major != Response.positiveIntermediate) { + throw new ZZError("unable to get: " + res.explanation); + } + + SubspaceDump sd; + try { + sd = new SubspaceDump(io); + } finally { + res = new Response(io.readline()); + if (res.major != Response.positiveCompletion) { + throw new ZZError("failed to get: " + res.explanation); + } + } + + // Delete the old subspace + if (basecell != null && basecell.s("d.ztp-subspace") != null) { + Subspace ss = new Subspace(basecell.s("d.ztp-subspace")); + String[] sdims = ss.getSoftDims(); + for (Enumeration e = ss.getCells(); e.hasMoreElements();) { + ZZCell c = (ZZCell)e.nextElement(); + + for (int i = 0; i < sdims.length; i++) { + if (c.s(sdims[i], 1) != null) c.disconnect(sdims[i], 1); + if (c.s(sdims[i], -1) != null) c.disconnect(sdims[i], -1); + } + if (c.s("d.ztp-subspace", 1) != null) c.disconnect("d.ztp-subspace", 1); + if (c.s("d.ztp-subspace", -1) != null) c.disconnect("d.ztp-subspace", -1); + } + } + + ZZDimSpace space = (ZZDimSpace)basecell.getSpace(); + + // Create the new subspace + { + ZZCell oc = basecell; + for (Enumeration e = sd.cellids.keys(); e.hasMoreElements();) { + String s = (String)e.nextElement(); + ZZCell c = space.getCellByID(s); + oc.connect("d.ztp-subspace", 1, c); + oc = c; + } + } + + for (Enumeration e = sd.content.keys(); e.hasMoreElements();) { + String s = (String)e.nextElement(); + ZZCell c = space.getCellByID(s); + c.setText((String)sd.content.get(s)); + } + for (Enumeration e = sd.dims.keys(); e.hasMoreElements();) { + String dimname = (String)e.nextElement(); + Hashtable dim = (Hashtable)sd.dims.get(dimname); + space.d(dimname); + for (Enumeration f = dim.keys(); f.hasMoreElements();) { + String s1 = (String)f.nextElement(); + String s2 = (String)dim.get(s1); + ZZCell c1 = space.getCellByID(s1); + ZZCell c2 = space.getCellByID(s2); + c1.connect(dimname, c2); + } + } + + +} + +} diff --git a/Modules/ztp/client/Subspace.java b/Modules/ztp/client/Subspace.java new file mode 100644 index 0000000..23a13d9 --- /dev/null +++ b/Modules/ztp/client/Subspace.java @@ -0,0 +1,76 @@ +/* +Put.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ + +package org.gzigzag.ztp.client; +import org.gzigzag.ztp.*; +import org.gzigzag.*; +import java.util.*; + +class Subspace { + + private String[] sdims; + private Hashtable cells = new Hashtable(); + + public String[] getSoftDims() { return sdims; } + public Enumeration getCells() { return cells.keys(); } + + public Subspace(ZZCell base) { + String[] origdims = base.getSpace().dims(); + Vector dimv = new Vector(); + + for (int i = 0; i < origdims.length; i++) { + if (origdims[i].equals("d.ztp-subspace") + || origdims[i].equals("d.cellcreation")) { + continue; + } + dimv.addElement(origdims[i]); + } + + sdims = new String[dimv.size()]; + for (int i = 0; i < sdims.length; i++) { + sdims[i] = (String)dimv.elementAt(i); + } + + if (base == null) return; + + Stack stack = new Stack(); + stack.push(base); + Hashtable seen = new Hashtable(); + while (!stack.empty()) { + ZZCell c = (ZZCell)stack.pop(); + + for (int i = 0; i < sdims.length; i++) { + ZZCell d = c.s(sdims[i], 1); + if (d != null && !seen.containsKey(d)) { + stack.push(d); + seen.put(d, d); + } + d = c.s(sdims[i], -1); + if (d != null && !seen.containsKey(d)) { + stack.push(d); + seen.put(d, d); + } + } + cells.put(c, c); + } + } + +} diff --git a/Modules/ztp/common/LineBufferedIO.java b/Modules/ztp/common/LineBufferedIO.java new file mode 100644 index 0000000..95d76de --- /dev/null +++ b/Modules/ztp/common/LineBufferedIO.java @@ -0,0 +1,111 @@ +/* +LineBufferedIO.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp; +import org.gzigzag.module.*; +import org.gzigzag.*; +import java.io.*; + +/** Line-buffered UTF-8 I/O. */ +public class LineBufferedIO { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log(s); } + private static void pa(String s) { ZZLogger.log(s); } + + InputStream in; + OutputStream out; + String buffer = new String(); + public LineBufferedIO(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + public synchronized void flush() throws IOException { + for (int i = 0; i < buffer.length(); i++) { + UTF8Char ch = new UTF8Char(buffer.charAt(i)); + out.write(ch.b, 0, ch.b.length); + } + out.flush(); + if (buffer.charAt(buffer.length()-1) == '\n') { + p("==> " + buffer.substring(0, buffer.length()-1)); + } else { + p("==> " + buffer); + } + buffer = ""; + } + public synchronized void write(String s) throws IOException { + for (int i = 0; i < s.length(); i++) { + buffer += s.charAt(i); + if (s.charAt(i) == '\n') flush(); + } + } + public synchronized void writeln(String s) throws IOException { + write(s + "\n"); + } + + private boolean ineof = false; + + public boolean isEOF() { return ineof; } + + /** Reads one UTF-8 character. If EOF is reached, the EOF + * flag is set and the returned value will be undefined. */ + public char getc() throws IOException { + if (ineof) return '\n'; + int o = in.read(); + if (o == -1) { + ineof = true; + return '\n'; + } + int len = UTF8Char.UTF8Len((byte) o); + byte[] bs = new byte[len]; + bs[0] = (byte)o; + for (int i = 1; i < len; i++) { + o = in.read(); + if (o == -1) { + ineof = true; + throw new IOException("file ended before char was complete"); + } + bs[i] = (byte)o; + } + return (new UTF8Char(bs)).c; + } + + /* Reads until the end of line (including the EOL character), + * or to EOF. */ + public String readline() throws IOException { + String rv = new String(); + + char c; + do { + c = getc(); + if (isEOF()) break; + rv += c; + } while (c != '\n'); + + if (rv.charAt(rv.length()-1) == '\n') { + p("<== " + rv.substring(0, rv.length()-1)); + } else { + p("<== " + rv); + } + return rv; + } + +} + diff --git a/Modules/ztp/common/SubspaceDump.java b/Modules/ztp/common/SubspaceDump.java new file mode 100644 index 0000000..c41c599 --- /dev/null +++ b/Modules/ztp/common/SubspaceDump.java @@ -0,0 +1,134 @@ +/* +SubspaceDump.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp; +import org.gzigzag.*; +import java.io.*; +import java.util.*; + +public class SubspaceDump { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + public static class AbortedException extends ZZError { + public AbortedException(String s) { + super(s); + } + } + + /** Cell content. This hashtable maps cell IDs into cell + * content. */ + public Hashtable content = new Hashtable(); + + /* Dimensions. This hashtable maps dimension names into + * hashtables that map cells to cells (key connected to datum + * posward along the dimension). */ + public Hashtable dims = new Hashtable(); + + + /* Cell IDs. This hashtable contains an entry for every cell that + * has a content entry or a connection entry. */ + public Hashtable cellids = new Hashtable(); + + public SubspaceDump(LineBufferedIO io) throws IOException { + boolean ok = true; + while (!io.isEOF()) { + try { + String line = io.readline(); + ZTPCommand cmd = new ZTPCommand(line); + + if (cmd.name.toUpperCase().equals("C")) { + if (cmd.args.length != 2) { + p("C args len = " + cmd.args.length); + ok = false; + continue; + } + Object o = content.get(cmd.args[0]); + String s = ""; + if (o != null) s = (String)o; + s += cmd.args[1]; + content.put(cmd.args[0], s); + cellids.put(cmd.args[0], cmd.args[0]); + } else if (cmd.name.toUpperCase().equals("R")) { + if (cmd.args.length < 3) { + p("R args len = " + cmd.args.length); + ok = false; + continue; + } + Hashtable dim = (Hashtable)dims.get(cmd.args[0]); + if (dim == null) { + dim = new Hashtable(); + dims.put(cmd.args[0], dim); + } + for (int i = 1; ok && i + 1 < cmd.args.length; i++) { + Object o = dim.get(cmd.args[i]); + if (o != null && !((String)o).equals(cmd.args[i+1])) { + p("existing connection (" + cmd.args[i] + ", " + (String)o + ") will be broken"+ + " by new connection (" + cmd.args[i] + ", " + cmd.args[i+1]); + ok = false; + continue; + } + dim.put(cmd.args[i], cmd.args[i+1]); + cellids.put(cmd.args[i], cmd.args[i]); + cellids.put(cmd.args[i+1], cmd.args[i+1]); + } + } else if (cmd.name.toUpperCase().equals("F")) { + break; + } else if (cmd.name.toUpperCase().equals("A")) { + throw new AbortedException("Subspace data transfer aborted"); + } else { + p("unknown command"); + ok = false; + continue; + } + } catch (SyntaxError e) { + ZZLogger.exc(e); + ok = false; + } + } + if (!ok) throw new SyntaxError("Syntax error is subspace data"); + } + + public static void dump(LineBufferedIO io, Enumeration cells, + String[] sdims, String prefix) throws IOException { + + for (; cells.hasMoreElements();) { + ZZCell c = (ZZCell)cells.nextElement(); + String cid = c.getGlobalID().substring(prefix.length()); + p("cell " + c); + io.writeln("C " + ZTPCommand.encode(cid) + " " + ZTPCommand.encode(c.getText())); + // Find connections from this cell + for (int i = 0; i < sdims.length; i++) { + String dim = sdims[i]; + p("dim " + dim); + ZZCell d = c.s(prefix + dim); + if (d != null) { + if (!d.getGlobalID().substring(0, prefix.length()).equals(prefix)) continue; + String did = d.getGlobalID().substring(prefix.length()); + io.writeln("R " + ZTPCommand.encode(dim) + + " " + ZTPCommand.encode(cid) + + " " + ZTPCommand.encode(did)); + } + } + } + io.writeln("F"); + } +} diff --git a/Modules/ztp/server/GetMessage.java b/Modules/ztp/server/GetMessage.java new file mode 100644 index 0000000..ed940b6 --- /dev/null +++ b/Modules/ztp/server/GetMessage.java @@ -0,0 +1,112 @@ +/* +PutMessage.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.server; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.io.*; +import java.util.*; + +class GetMessage implements Session.Message { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + static String prefix = PutMessage.prefix; + + public String name() { return "GET"; } + public String help() { return "Gets a subspace from the server"; } + public int prereqs() { return Session.FL_AUTH; } + + public void invoke(Session sess, String[] args) throws IOException { + LineBufferedIO io = sess.getIO(); + ZZSpace space = sess.space; + if (args.length != 1) { + io.writeln("5.0.1 Syntax: GET "); + return; + } + + if (!args[0].equals("ALL")) { + io.writeln("5.4.1 No such subspace"); + return; + } + + io.writeln("3.4.1 Proceeding with subspace data ..."); + + synchronized (space) { + // Find all relevant dimensions + String[] dims; + { + Vector dimv = new Vector(); + for (ZZCell c = space.getHomeCell().s("d.masterdim", 1); c != null; + c = c.s("d.masterdim", 1)) { + String name = c.getText(); + if (name.length() >= prefix.length() + && name.substring(0, prefix.length()).equals(prefix)) { + dimv.addElement(name.substring(prefix.length())); + } + } + dims = new String[dimv.size()]; + for (int i = 0; i < dims.length; i++) { + dims[i] = (String)dimv.elementAt(i); + } + } + + class Enum implements Enumeration { + Enumeration e; + Object cur; + private void Cur() { + cur = null; + while (e.hasMoreElements()) { + cur = e.nextElement(); + ZZCell c = (ZZCell)cur; + p("considering " + c); + if (c.getID().substring(0, prefix.length()).equals(prefix)) + p("OK"); + break; + } + } + public Enum(Enumeration e) { + this.e = e; + Cur(); + } + public boolean hasMoreElements() { + return cur != null; + } + public Object nextElement() { + Object rv = cur; + if (rv == null) throw new NoSuchElementException(); + Cur(); + p("nextElement = " + rv); + return rv; + } + }; + + SubspaceDump.dump(io, + new Enum(space.getHomeCell().s("d.ztpspace").enumRank("d.ztpspace")), + dims, prefix); + + } + + io.writeln("2.4.1 Subspace successfully got"); + + } + +} diff --git a/Modules/ztp/server/Listener.java b/Modules/ztp/server/Listener.java new file mode 100644 index 0000000..51ef450 --- /dev/null +++ b/Modules/ztp/server/Listener.java @@ -0,0 +1,55 @@ +/* +Listener.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.server; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.net.*; +import java.io.*; + +public class Listener extends Thread { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + private ZZSpace space; + private ServerSocket lsock; + public Listener(ZZSpace space, ServerSocket lsock) { + this.space = space; + this.lsock = lsock; + } + public void run() { + pa("Listener starts"); + while (!isInterrupted()) { + try { + p("waiting for connections"); + Socket csock = lsock.accept(); + p("connection request received"); + Session sess = new Session(space, csock); + sess.start(); + } catch (IOException e) { + ZZLogger.exc(e); + } + + } + pa("Listener stops"); + } +} + diff --git a/Modules/ztp/server/PutMessage.java b/Modules/ztp/server/PutMessage.java new file mode 100644 index 0000000..f6a147c --- /dev/null +++ b/Modules/ztp/server/PutMessage.java @@ -0,0 +1,117 @@ +/* +PutMessage.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.server; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.io.*; +import java.util.*; + +class PutMessage implements Session.Message { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + static String prefix = "ztpspace!"; + + public String name() { return "PUT"; } + public String help() { return "Puts a subspace to the server"; } + public int prereqs() { return Session.FL_AUTH; } + + public void invoke(Session sess, String[] args) throws IOException { + LineBufferedIO io = sess.getIO(); + ZZSpace space = sess.space; + if (args.length != 1) { + io.writeln("5.0.1 Syntax: PUT "); + return; + } + + if (!args[0].equals("ALL")) { + io.writeln("5.4.1 No such subspace"); + return; + } + + io.writeln("3.4.0 Please proceed with subspace data, end with 'F'"); + + + SubspaceDump sd; + try { + sd = new SubspaceDump(io); + } catch (SubspaceDump.AbortedException e) { + io.writeln("5.4.0 " + e.getMessage()); + return; + } catch (SyntaxError e) { + io.writeln("5.0.1 " + e.getMessage()); + return; + } + + // Verify that the cells all have a good ID. + for (Enumeration e = sd.cellids.keys(); e.hasMoreElements();) { + String s = (String)e.nextElement(); + if (s.indexOf("@") == -1) { + io.writeln("5.4.2 Cannot put cells lacking a space ID"); + return; + } + } + + synchronized (space) { + // Delete old subspace + for (ZZCell c = space.getHomeCell().s("d.ztpspace", 1); c != null; ) { + ZZCell s = c.s("d.ztpspace", 1); + if (c.getID().substring(0, prefix.length()).equals(prefix)) { + c.delete(); + } + c = s; + } + + // Create the new subspace + { + ZZCell oc = space.getHomeCell(); + for (Enumeration e = sd.cellids.keys(); e.hasMoreElements();) { + String s = (String)e.nextElement(); + ZZCell c = space.getCellByID(prefix + s); + oc.connect("d.ztpspace", 1, c); + oc = c; + } + } + for (Enumeration e = sd.content.keys(); e.hasMoreElements();) { + String s = (String)e.nextElement(); + ZZCell c = space.getCellByID(prefix + s); + c.setText((String)sd.content.get(s)); + } + for (Enumeration e = sd.dims.keys(); e.hasMoreElements();) { + String dimname = (String)e.nextElement(); + Hashtable dim = (Hashtable)sd.dims.get(dimname); + ((ZZDimSpace)space).d(dimname); + for (Enumeration f = dim.keys(); f.hasMoreElements();) { + String s1 = (String)f.nextElement(); + String s2 = (String)dim.get(s1); + ZZCell c1 = space.getCellByID(prefix + s1); + ZZCell c2 = space.getCellByID(prefix + s2); + c1.connect(prefix + dimname, c2); + } + } + space.commit(); + } + io.writeln("2.4.0 Subspace successfully put"); + } + + +} diff --git a/Modules/ztp/server/Session.java b/Modules/ztp/server/Session.java new file mode 100644 index 0000000..63113c4 --- /dev/null +++ b/Modules/ztp/server/Session.java @@ -0,0 +1,227 @@ +/* +Session.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.server; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.net.*; +import java.io.*; +import java.util.*; + +public class Session extends Thread { + public static boolean dbg = false; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + public ZZSpace space; + private Socket socket = null; + + interface Message { + String name(); + String help(); + int prereqs(); + void invoke(Session sess, String[] args) throws IOException; + } + + private LineBufferedIO io; + + private boolean proper_close = false; + + public LineBufferedIO getIO() { return io; } + + private UserManager userManager; + + public UserManager getUserManager() { return userManager; } + + // prereq constants (orred) + static final int FL_AUTH = 1; + static final int FL_SAP = 2; + + private int reqstatus; + + public String user; + + public void setFlag(int flag) { reqstatus |= flag; } + public void clearFlag(int flag) { reqstatus &= ~flag; } + + private void login(UserRecord ur) throws IOException { + try { + if (ur.sap) { + setFlag(FL_SAP); + } else { + clearFlag(FL_SAP); + } + user = ur.username; + setFlag(FL_AUTH); + io.writeln("2.3.0 OK"); + if (socket != null) { + pa("connection from " + socket.getInetAddress().getHostName() + + " authenticated as " + user); + } + } catch (Throwable e) { + clearFlag(FL_AUTH); + ZZLogger.exc(e); + io.writeln("4.3.0 Problem authenticating user"); + } + } + + Message[] messages = { + new Message() { + public String name() { return "QUIT"; } + public String help() { return "Quit the session"; } + public int prereqs() { return 0; } + public void invoke(Session ses, String[] args) throws IOException { + clearFlag(FL_AUTH); + ses.interrupt(); + ses.proper_close = true; + ses.io.writeln("2.2.1 Be seeing you"); + } + }, + new Message() { + public String name() { return "AUTH/PRE"; } + public String help() { return "Request preauthentication"; } + public int prereqs() { return 0; } + public void invoke(Session ses, String[] args) throws IOException { + LineBufferedIO io = ses.getIO(); + if (args.length != 1) { + io.writeln("5.0.1 Syntax: AUTH/PRE "); + return; + } + UserRecord ur = ses.getUserManager().access(args[0]); + if (ur == null || !ur.auth_pre) { + io.writeln("5.3.0 Access denied"); + return; + } + if (ur.susp) { + io.writeln("5.3.1 User disabled"); + return; + } + ses.login(ur); + } + }, + new Message() { + public String name() { return "AUTH/PASS"; } + public String help() { return "Request password authentication"; } + public int prereqs() { return 0; } + public void invoke(Session ses, String[] args) throws IOException { + LineBufferedIO io = ses.getIO(); + if (args.length != 2) { + io.writeln("5.0.1 Syntax: AUTH/PASS "); + return; + } + UserRecord ur = ses.getUserManager().access(args[0]); + if (ur == null || !ur.auth_pass || !ur.password.equals(args[1])) { + io.writeln("5.3.0 Access denied"); + return; + } + if (ur.susp) { + io.writeln("5.3.1 User disabled"); + return; + } + ses.login(ur); + } + }, + new PutMessage(), + new GetMessage() + }; + + private static Hashtable sessions = new Hashtable(); + + + public static Enumeration getActiveSessions() { + synchronized (sessions) { + return sessions.keys(); + } + } + + public Session(ZZSpace space, Socket sock) throws IOException { + this(space, sock.getInputStream(), sock.getOutputStream()); + socket = sock; + } + + public Session(ZZSpace space, InputStream in, OutputStream out) throws IOException { + this.space = space; + io = new LineBufferedIO(in, out); + socket = null; + } + + public void run() { + try { + p("session start"); + if (socket != null) { + pa("accepting connection from " + socket.getInetAddress().getHostName()); + } + userManager = UserManager.create(space); + synchronized (sessions) { + sessions.put(this, this); + } + try { + io.writeln("2.2.0 Hello there!"); + } catch (IOException e) { + ZZLogger.exc(e); + } + while (!io.isEOF() && !isInterrupted()) { + try { + try { + String line = io.readline(); + p("read " + line); + ZTPCommand c = new ZTPCommand(line); + p("" + c); + Message m = null; + for (int i = 0; i < messages.length; i++) { + if (messages[i].name().toUpperCase().equals(c.name.toUpperCase())) { + m = messages[i]; + } + } + if (m == null) { + io.writeln("5.0.1 What?"); + } else { + if (((m.prereqs() & reqstatus) ^ m.prereqs()) == 0) { + m.invoke(this, c.args); + } else { + io.writeln("5.0.2 Permission denied"); + } + } + } catch (SyntaxError e) { + io.writeln("5.0.1 " + e.getMessage()); + } + } catch (IOException e) { + ZZLogger.exc(e); + } + } + } finally { + synchronized (sessions) { + try { + if (!proper_close) io.writeln("4.2.1 Aborting"); + socket.close(); + } catch (IOException e) { + ZZLogger.exc(e); + } + sessions.remove(this); + } + userManager.close(); + } + if (socket != null) { + pa("closing connection from " + socket.getInetAddress().getHostName()); + } + p("session end"); + } +} + diff --git a/Modules/ztp/server/UserManager.java b/Modules/ztp/server/UserManager.java new file mode 100644 index 0000000..ba025a0 --- /dev/null +++ b/Modules/ztp/server/UserManager.java @@ -0,0 +1,139 @@ +/* +UserManager.java + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.server; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.util.*; + +/** User manager for ZTP server. It enforces single-threaded access + * to the user table in the space. */ +class UserManager { + public static boolean dbg = true; + private static void p(String s) { if(dbg) ZZLogger.log("[" + s + "]"); } + private static void pa(String s) { ZZLogger.log(s); } + + private static Hashtable managers = new Hashtable(); + + private int refcount; + + private ZZSpace space; + + private boolean live = false; + + private void assertLiving() { + if (!live) throw new ZZError("UserManager closed"); + } + + /* + private ZZCell userlist; + */ + + private UserManager(ZZSpace space) { + synchronized (managers) { + this.space = space; + if (managers.containsKey(space)) { + throw new ZZError("there already is a UserManager for that space"); + } + managers.put(space, this); + live = true; + } + + refcount = 0; + + // NOT NOW + //// we find the user list here for convenience + //ZZCell home = space.getHomeCell(); + //userlist = home.findText("d.system", 1, "ZTPUserList"); + //if (userlist == null) { + ///* userlist = home.N("d.system", 1); + //userlist.setText("ZTPUserList");*/ + //throw new ZZError("no user list in space!"); + //} + } + + + public static UserManager create(ZZSpace space) { + UserManager rv; + synchronized (managers) { + Object o = managers.get(space); + if (o == null) { + rv = new UserManager(space); + } else { + rv = (UserManager)o; + } + } + ++rv.refcount; + return rv; + } + + public void close() { + if (--refcount < 1) { + synchronized (managers) { + live = false; + managers.remove(space); + } + } + } + + public synchronized UserRecord access(String username) { + assertLiving(); + + UserRecord rv = new UserRecord(); + + rv.username = "adm"; + rv.password = "mda"; + rv.susp = false; + rv.chpass = false; + rv.sap = true; + rv.auth_pre = true; + rv.auth_pass = true; + + return username.equals(rv.username) ? rv : null; + } + + public interface RecordHandler { + void doit(UserRecord ur); + } + + public synchronized void access_atomic(String username, RecordHandler rh) { + UserRecord ur = access(username); + rh.doit(ur); + } + + public synchronized void replace(UserRecord ur) { + throw new ZZError("user record replace not implemented at this time"); + } + + public synchronized void replace_atomic(String username, RecordHandler rh) { + UserRecord ur = access(username); + rh.doit(ur); + replace(ur); + } + + public synchronized void delete(String uname) { + throw new ZZError("user record deletion not implemented at this time"); + } + + public synchronized void insert(UserRecord ur) { + throw new ZZError("user record insertion not implemented at this time"); + } + +} diff --git a/Modules/ztp/server/UserRecord.zob b/Modules/ztp/server/UserRecord.zob new file mode 100644 index 0000000..1a91549 --- /dev/null +++ b/Modules/ztp/server/UserRecord.zob @@ -0,0 +1,56 @@ +/* +UserRecord.zob + * + * You may use and distribute under the terms of either the GNU Lesser + * General Public License, either version 2 of the license or, + * at your choice, any later version. Alternatively, you may use and + * distribute under the terms of the XPL. + * + * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of + * the licenses. + * + * This software 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 README + * file for more details. + * + */ +/* + * Written by Antti-Juhani Kaijanaho + */ +package org.gzigzag.ztp.server; +import org.gzigzag.*; +import org.gzigzag.ztp.*; +import java.util.*; + +/** User manager for ZTP server. It enforces single-threaded access + * to the user table in the space. */ + +public class UserRecord implements ZOb { + + STRUCTPARAMS { + /** The username. */ + String username; + + /** The password for AUTH/PASS. */ + String password; + + /** Is the user suspended? */ + boolean susp; + + /** Is the user allowed to change her password? */ + boolean chpass; + + /** Does the user have Space Administrator Privileges? */ + boolean sap; + + /** May the user use preauthentication? */ + boolean auth_pre; + + /** May the user use password authentication? */ + boolean auth_pass; + } + + +} + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..b5172bb --- /dev/null +++ b/NEWS @@ -0,0 +1,207 @@ +=============================== -*- Text -*- +User-visible changes in GZigZag +=============================== + + +The 0.6 Series +============== + + +0.6.3 (2002-03-07) +----- + +The following features have been added: +- A PUICOPYRANK action (bound by default to Ctrl-Alt-C) has + been added. It copies the cell contents along the y-dimension + rank to the PUI clipboard, inserting newlines between cells. + +The following features have been improved: +- The Row and Column views have been fixed to show the dimensions + always. Previously, in some common cases the dimensions were hidden + under the cells shown by the views. +- The Ball-and-Strick cell view now does line breaking. +- The Prez (presentation) module has been changed so that its view + now uses the dimension settings (x, y and z axis) instead of fixed + dimension names (d.1, d.2 and d.3), and to work with circular ranks. + +The following bugs have been fixed: +- The mindmapping module is now included in the official jars. +- Documentation/index.html had a HTML error; this is now fixed. + + +0.6.2 (2002-02-16) +----- + +A bug that made GZigZag not run on Java 1.2 and above has been fixed. +GZZ does not compile correctly with IBM's jikes 1.15 now; Sun's javac +works (you may also want to try jikes 1.14). + +The following new features have been added: +- Asko Soukka's MindSundew and MindSun views, providing a mindmapping-like + interface to the ZZ structure. They works together nicely with the common + key bindings. You can find them under AllViews after creating a new space, + or re-generating the system part of an old space using the '-new' + command line option. + + Note that these views are only available in versions of GZigZag that + include this module. + +The following features have been improved: +- The row/column views show like they did previous to version 0.3.0, again. + + + +0.6.1 (2001-08-17) +----- + +Flowing Clang has been brought back to life (it wasn't included in some +previous releases due to lack of interest). + +The following new features have been added: + - The EDITHACK action (found on the actions list), which allows opening + a window for text editing. Java's AWT classes are used, which have + support for mouse selection, the PUI clipboard, and entering Japanese + characters, among other things. (For internal reasons, the text window + is not automatically re-opened when the client starts again; the + EDITHACK action has to be executed again.) + + +0.6.0 +----- + +Support for the old "PersistentDimSpace" file format has been removed. + +The following new features have been added: + - A preliminary ZigZag Transfer Protocol (ZTP) implementation + - space dump and slurp functionality (for disaster recovery + and format conversions) + - accessing past versions of the space + - a panic button + - demo module: associative writing tool - a multilayered concept map + - a -help option to the command line + - a multiline cell view + - support for cell-view specific bindings: when a cell view is associated + with a cell in the structure (per d.cellview connection), in the cell + edit mode bindings associated with that cellview can be used (so that + content which isn't plain text can be edited easily) + +The following features have been improved: + - the user's guide + - the multimedia module + - the virtual community module + - sound support + - view infrastructure + +The following notable bug fixes have been made: + - the new UTF-8-based string scroll format actually works now + - umlauts aren't doubled (don't appear twice when entered only once) + + +The 0.5 Series +============== + +The following new features have been added: + - Notemap Star view, a view showing a map of cells connected in a network + structure + - Parallel (Split) Nile View, a view which places two Nile streams next to + each other and shows transclusions with beams + - A preliminary multimedia module + - A prototype virtual community module + + +The 0.4 Series +============== + +The following new features have been added: + - A new UTF-8-based string scroll format (used in new scrolls; + existing scrolls continue to use the old format) + - a prototype NILE (NILE Is A Literary Editor) + - Zaubertrank + - F1 is help + + +The 0.3 Series +============== + + +Release 0.3.0 (2000-11-21) +------------- + +The following new features have been added: + - a new user's guide (work in progress, but already very useful) + - Heraclitus Clang + - XOR mode cursors + - Text find + - Flowing Clang + - Internationalization + - Calendar demo + - IC View + - Cursor View + - Rewritten XML import / export + - Wordnet applitude + - ball&stick model + - split vanishing into vanishing and rowcol + - nicer geometry for rowcol + - new, interesting parameters for vanishing: revper, halign + *** REQUIRES RECREATION OF SYSTEM PART *** + - ZOb's names are now class names. + +The following internal changes have been made + - huge API change to shorter core function names in ZZCell + + +The 0.2 Series +============== + +The 0.2 series was never released. + + +The 0.1 Series +============== + + +Release 0.1.5 (2000-11-02) +------------- + +This release contains the following bug fixes: + - Undoing a cell creation no longer throws an exception + - Compass and Presentation Views are now in AllViews list + + +Release 0.1.4 (2000-10-25) +------------- + +This release contains the following user-visible changes: + - The keys Ctrl-A, Ctrl-E, Home, End and Enter now work in edit + mode + - There is a new -recrmdim option, which will recreate a damaged + master dimension list (useful in converting old spaces) + - XML export and import bug fixes, including a new -xmlencoding + option for specifying the XML character encoding to use at export + time. + + +Release 0.1.3 (2000-10-09) +------------- + +This release contains the following bug fixes: + - The Mbox module works again + - Edit view background is now all-white + + +Release 0.1.2 (2000-09-28) +------------- + +This release fixes a packaging goofup in 0.1.1. + + +Release 0.1.1 (2000-09-28) +------------- + +This release contains no user-visible changes. + + +Release 0.1.0 (2000-09-26) +------------- + +This is the first public release. diff --git a/Perl/PerlServImpl.pm b/Perl/PerlServImpl.pm new file mode 100644 index 0000000..4de5e6f --- /dev/null +++ b/Perl/PerlServImpl.pm @@ -0,0 +1,63 @@ +# +# PerlServImpl.pm +# +# Copyright (c) 1999, Tuomas Lukka +# +# You may use and distribute under the terms of either the GNU Lesser +# General Public License, either version 2 of the license or, +# at your choice, any later version. Alternatively, you may use and +# distribute under the terms of the XPL. +# +# See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# the licenses. +# +# This software 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 README +# file for more details. + + +FOR A MODEL ONLY - COPY & IMPLEMENT + +# ref & lock handled by the sessions... + +# gethead, sethead not implemented +# +sub _c_get { + my($this, $sess, $cfrom, $dim, $dir) = @_; +} +sub _c_new { + my($this, $sess, $cfrom, $dim, $dir) = @_; +} +sub _c_delete { + my($this, $sess, $cell) = @_; +} +sub _c_connect { + my($this, $sess, $cfrom, $dim, $cto) = @_; +} +sub _c_insert { + my($this, $sess, $cfrom, $dim, $dir, $cto) = @_; +} +sub _c_disconnect { + my($this, $sess, $cfrom, $dim, $dir) = @_; +} +sub _c_gettext { + my($this, $sess, $cell) = @_; +} +sub _c_settext { + my($this, $sess, $cell) = @_; +} +sub _c_ref { + my($this, $cell, $ref) = @_; +} +sub _c_lock { + my($this, $cell, $lock) = @_; +} +sub _c_unlock { + my($this, $cell, $lock) = @_; +} +sub _c_execute { + my($this, $script, $obj, $ctrl, $view) = @_; +} + + diff --git a/Perl/README b/Perl/README new file mode 100644 index 0000000..8e9351a --- /dev/null +++ b/Perl/README @@ -0,0 +1,5 @@ +This directory contains various hacks related to the client-server +protocol. Not necessarily usable in its current form. Use the stuff +in the ../Java/ directory. + + Tuomas diff --git a/Perl/ZZPerlDBServ.pm b/Perl/ZZPerlDBServ.pm new file mode 100644 index 0000000..4cfcd3a --- /dev/null +++ b/Perl/ZZPerlDBServ.pm @@ -0,0 +1,137 @@ +# +# ZZPerlDBServ.pm +# +# Copyright (c) 1999, Tuomas Lukka +# +# You may use and distribute under the terms of either the GNU Lesser +# General Public License, either version 2 of the license or, +# at your choice, any later version. Alternatively, you may use and +# distribute under the terms of the XPL. +# +# See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# the licenses. +# +# This software 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 README +# file for more details. + + +package ZZPHash; +require Tie::Hash; +@ISA='Tie::StdHash'; +sub TIEHASH { + bless $_[1], $_[0]; +} +sub STORE { + $_[0]->{$_[1]} = $_[2]; + print "STORED: '$_[1]' '$_[2]'\n"; +} +sub DELETE { + my $r0 = $_[0]->{$_[1]}; + my $r = delete $_[0]->{$_[1]}; + print "DELETED: '$_[1]' ( = '$r0' '$r')\n"; + return $r0; +} + +sub sync { tied (%{$_[0]})->sync } + +package ZZPerlDBServ; +use base ZZPerlServ; +use DB_File; + +sub _init_zzspace { + my($this) = @_; + my $db = $this->{DB}; + $db->{1} = "Home"; + $db->{Newno} = 42; + $db->{Inited} = 1; +} + +sub _c__reallynew { + my($this) = @_; + my $n = $this->{DB}->{Newno}++; + $db->{$n} = ""; + return $n; +} + +sub new { + my($type, $id, $port, $dbf) = @_; + my $this = $type->SUPER::new($id,$port); + my %h; + tie %h, DB_File, $dbf, &O_RDWR|&O_CREAT, 0640, $DB_HASH; + $this->{DB} = \%h; + my %h2; + tie %h2, ZZPHash, $this->{DB}; + $this->{DB} = \%h2; + $this->_init_zzspace() unless $this->{DB}{Inited}; + + Event->timer( + interval => 2, + cb => sub { $this->sync() } + ); + return $this; +} + +# gethead, sethead not implemented +# +sub _c_get { + my($this, $sess, $cfrom, $dim, $dir) = @_; + my $c = $this->{DB}{$cfrom.$dir.$dim}; + $c += 0; # Undef -> 0 + return $c; +} + +sub _c_delete { + my($this, $sess, $cell) = @_; + my @chg; + for(@{$this->{Dims}}) { + my $c; + push @chg, $c = delete $this->{DB}{$cell."+".$_}; + delete $this->{DB}{$c."-".$_} if $c; + push @chg, $c = delete $this->{DB}{$cell."-".$_}; + delete $this->{DB}{$c."+".$_} if $c; + } + push @chg; + $this->_chg(\@chg); + $this->_del($cell); +} +sub _c_connect { + my($this, $sess, $cfrom, $dim, $cto) = @_; + my @chg; + print "C_CONN $cfrom $dim $cto\n"; + my $c; + push @chg, $c = delete $this->{DB}{$cfrom."+".$dim}; + delete $this->{DB}{$c."-".$dim} if $c; + push @chg, $c = delete $this->{DB}{$cto."-".$dim}; + delete $this->{DB}{$c."+".$dim} if $c; + $this->{DB}{$cfrom."+".$dim} = $cto; + $this->{DB}{$cto."-".$dim} = $cfrom; + $this->_chg(@chg, $cfrom, $cto); +} +sub _c_disconnect { + my($this, $sess, $cfrom, $dim, $dir) = @_; + print "C_DISCONN $cfrom $dim $dir\n"; + my $c = delete $this->{DB}{$cfrom.$dir.$dim}; + return unless $c; + delete $this->{DB}{$c.(ZZPerlServ::oppdir($dir)).$dim}; + $this->_chg($cfrom, $c); +} +sub _c_gettext { + my($this, $sess, $cell) = @_; + my $v = $this->{DB}{$cell}; + if(!defined $v) { + return "" if exists $this->{DB}{$cell}; + return undef; + } + return $v; +} +sub _c_settext { + my($this, $sess, $cell, $text) = @_; + $this->{DB}{$cell} = $text; + $this->_chg($cell); +} + +sub sync { my($this) = @_; (tied %{$this->{DB}})->sync } + +1; diff --git a/Perl/ZZPerlServ.pm b/Perl/ZZPerlServ.pm new file mode 100644 index 0000000..96ea8c4 --- /dev/null +++ b/Perl/ZZPerlServ.pm @@ -0,0 +1,410 @@ +# +# ZZPerlServ.pm +# +# Copyright (c) 1999, Tuomas Lukka +# +# You may use and distribute under the terms of either the GNU Lesser +# General Public License, either version 2 of the license or, +# at your choice, any later version. Alternatively, you may use and +# distribute under the terms of the XPL. +# +# See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# the licenses. +# +# This software 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 README +# file for more details. + + + + +package ZZPerlServ; +use Event; +use IO::Socket; + +sub oppdir { + return "-" if $_[0] eq "+"; + return "+" if $_[0] eq "-"; + die("INVALID DIR!"); +} + +sub new { + my($type, $id, $port) = @_; + my $fh = IO::Socket::INET->new( + Proto => 'tcp', + LocalPort => $port, + Listen => SOMAXCONN, + Reuse => 1 + ); + my $this = bless { + Id => $id, + ConnId => 42, + FH => $fh, + }, $type; + Event->io( + fd => $fh, + poll => 're', + cb => sub { + my $cfh = $fh->accept() + or die("Couldn't set up client"); + # XXX autoflush? + $this->newconnection($cfh); + } + ); + Event->idle( + max => 2, + cb => sub { + $this->flush_changes(); + } + ); + return $this; +} + +sub newconnection { + my($this, $fh) = @_; + my $c = bless { + FH => $fh, + S => $this, + Id => $this->{ConnId}++, + }, ZZPerlConn; + $this->{Sess}{$c} = $c; + # XXX Weaken!!! + $c->start(); +} + +sub _c_new { + my($this, $sess, $cfrom, $dim, $dir) = @_; + my $cur = $this->{DB}{$cfrom.$dir.$dim}; + my $new = $this->_c__reallynew($sess); + if(!$new) { + return (0, "Couldn't create"); + } + if($dir eq "-") { + ($cfrom, $cur) = ($cur, $cfrom); + } + # XXX Catch errors + $this->_c_connect($sess, $cfrom, $dim, $new) + if $cfrom; + $this->_c_connect($sess, $new, $dim, $cur) + if $cur; + return ($new,""); +} + +sub _c_insert { + my($this, $sess, $cfrom, $dim, $dir, $cto) = @_; + print "INSERT $cfrom $dim $dir $cto\n"; + my $cm = $this->_c_get($sess, $cto, $dim, "-"); + my $cp = $this->_c_get($sess, $cto, $dim, "+"); + if($cm && $cp) { + $this->_c_connect($sess, $cm, $dim, $cto); + } else { + print "CM: $cm CP: $cp\n"; + $this->_c_disconnect($sess, $cto, $dim, "-") if $cm; + $this->_c_disconnect($sess, $cto, $dim, "+") if $cp; + } + my $c = $this->_c_get($sess, $cfrom, $dim, $dir); + print "C: $c\n"; + # if($c == $cto) { + # return; + # } + if($dir eq "+") { + $this->_c_connect($sess, $cfrom, $dim, $cto); + $this->_c_connect($sess, $cto, $dim, $c) if $c; + } else { + $this->_c_connect($sess, $cto, $dim, $cfrom); + $this->_c_connect($sess, $c, $dim, $cto) if $c; + } +} + +sub _c_ref { + my($this, $sess, $cell, $ref) = @_; + if(($this->{Fer}{$sess}{$cell} += $ref) <= 0) { + delete $this->{Fer}{$sess}{$cell}; + } + if(($this->{Ref}{$cell}{$sess} += $ref) <= 0) { + delete $this->{Ref}{$cell}{$sess}; + if(!keys %{$this->{Ref}{$cell}}) { + delete $this->{Ref}{$cell}; + } + } +} + +sub _chg { + my $this = shift; + if(ref $_[0]) { + for(@{$_[0]}) { + $this->{Chg}{$_} = 1; + } + } else { + for(@_) { + $this->{Chg}{$_} = 1; + } + } +} + +sub _del { + my($this, $cell) = @_; + for my $sess (keys %{$this->{Ref}{$cell}}) { + $sess->change("-1 deleted($cell)\n"); + } + delete $this->{Ref}{$cell}; +} + +sub flush_changes { + my($this) = @_; + print "FLUSH!\n"; + for(keys %{$this->{Chg}}) { + print "CELL: $_\n"; + for my $sess (keys %{$this->{Ref}{$_}}) { + print "SESS: $sess CELL: $_\n"; + $this->{Sess}{$sess}->change("-1 changed($_)\n"); + } + } + %{$this->{Chg}} = (); +} + +# XXX What happens when deleting a cell being waited for locking +sub _c_lock { + my($this, $sess, $cell, $lock) = @_; + my $l = { + Sess => "$sess", + N => $lock+0, + }; + if($this->{Lock}{$cell}) { + if($lock =~ /w/) { + push @{$this->{Wait}{$cell}}, $l; + # This will disable the filehandle in select. + $this->{Waiting}{$sess} = 1; + } elsif($lock =~ /a/) { + push @{$this->{Wait}{$cell}}, $l; + } else { + #$sess->_send_wouldblock($cell); + } + } else { + $this->{Lock}{$cell} = $l; + if($lock =~ /a/) { + $sess->_send_locked($cell); + } + } +} + +sub del_sess { + my($this, $sess) = @_; + # XXX HANDLE LOCKS! + for(keys %{ $this->{Fer}{$sess} }) { + delete $this->{Ref}{$_}{$sess}; + } + delete $this->{Fer}{$sess}; + delete $this->{Sess}{$sess}; +} + +sub _c_unlock { + my($this, $sess, $cell, $lock) = @_; +} +sub _c_execute { + my($this, $sess, $script, $obj, $ctrl, $view) = @_; +} + + +# Subclasses must implement +# c_get, c_new, c_delete,... + +package ZZPerlConn; + +%clcom = ( +get => 5, +gethead => 5, +sethead => 3, +new => 5, +delete => 1, +connect => 3, +insert => 4, +disconnect => 3, +gettext => 1, +settext => 2, +ref => 2, +lock => 2, +unlock => 1, +execute => 4, +); +%bincom = map {($_=>1)} qw/settext/; + +%excom = ( +get => rl, +gethead => rl, +new => rl, +); + +%respcom = ( +get => cellno, +gethead => cellno, +sethead => ok, +new => cellno, +delete => ok, +connect => ok, +insert => ok, +disconnect => ok, +gettext => text, +settext => ok, +ref => +); + +my $ip = qr/\((.*?)\)/; +my @nip = ( + "", + qr/$ip/, + qr/$ip$ip/, + qr/$ip$ip$ip/, + qr/$ip$ip$ip$ip/, + qr/$ip$ip$ip$ip$ip/, +); + + +use Fcntl; + +sub start { + my($this) = @_; + $this->{FH}->print("ZZ(0.02)($this->{S}{Id})($this->{Id})\n"); + fcntl($this->{FH}, &O_NONBLOCK, $b); + $this->{FH}->autoflush(1); + $this->{State} = "init"; + my $buf = ""; + $this->{Watcher} = Event->io( + fd => $this->{FH}, + poll => 're', + cb => sub { + my $b; + print "GOTIN\n"; + my $l = $this->{FH}->sysread($b,1024); + if(!$l) { + $this->throwout(); return; + } + $buf .= $b; + TRYMORE: + my $got = 0; + print "BUF: '$buf'\n"; + if(exists $this->{Binary}) { + if(length($buf)>= $this->{Binary}) { + $got=1; + my $s = substr($buf, 0, $this->{Binary},""); + print "$this->{Binary} str: '$s'\n"; + $this->binary_input($s); + delete $this->{Binary}; + } + } else { + if($buf =~ /^(.*?)(?:\x0d\x0a?|\x0a\x0d?)/) { + $got=1; + my $line = $1; + chomp $line; + chomp $line; + $buf =~ s/^(.*?(?:\x0d\x0a?|\x0a\x0d?))//; + $this->input($line); + } + } + goto TRYMORE if $got; + } + ); +} + +sub throwout { + my($this, $msg) = @_; + print "THROWING OUT $this: $msg\n"; + return unless defined $this->{Watcher}; + $this->{Watcher}->cancel(); + $this->{S}->del_sess($this); +} + +sub input { + my($this, $line) = @_; + print "IN: '$line'\n"; + for($this->{State}) { + /normal/ and do { + # print join ',', map {ord} split '', $line; + # print "\n"; + $line =~ /^(\d+)\s+(\w+)/ or + die("Illegal line '$line'"); + my $comid = $1; + my $c = $2; + if(!$clcom{$c}) { + $this->throwout("Unknown command '$c'"); + return; + } + unless($line =~ /^\d+\s+\w+$nip[$clcom{$c}]$/) { + $this->throwout("Need $clcom{$c} params for $c"); + return; + } + my @pars = map {defined $_ ? $_ : ()} + ($1, $2, $3, $4, $5); + if($bincom{$c}) { + $this->{BC} = $c; + $this->{BCID} = $comid; + $this->{BP} = \@pars; + print "BPARS: @pars\n"; + $this->{Binary} = pop @pars; + print "Bin: $this->{Binary}\n"; + } else { + my $m = "_c_$c"; + my @l = $this->{S}->$m($this,@pars); + my $rc = $respcom{$c}; + if($rc eq "cellno") { + print "CELL: $l[0]\n"; + if(!$l[0]) { + # $this->{FH}->print("$comid error(FROM CELLNO $l[1])\n"); + # NO SUCH CELL + $this->{FH}->print("$comid cellno(0)\n"); + + last; + } + # assuming ref-lock. + my $ref = $pars[-2]; + my $lock = $pars[-1]; + print "REF: $ref\n"; + $this->{S}->_c_ref($this,$l[0], $ref) + if $ref; + $this->{S}->_c_lock($this,$l[0], $ref) + if $lock; + $this->{FH}->print("$comid cellno($l[0])\n"); + } elsif($rc eq "ok") { + $this->{FH}->print("$comid ok\n"); + } elsif($rc eq "text") { + if(!defined $l[0]) { + # $this->{FH}->print("$comid error(no such cell)\n"); + # last; + $l[0] = ""; + } + my $len = length $l[0]; + $this->{FH}->print("$comid text($pars[0])($len)\n$l[0]"); + } + print "REPLIED!\n"; + } + last; + }; + /init/ and do { + unless($line =~ /^ZZ$ip$ip$ip$/) { + $this->throwout("Invalid startline"); + return; + } + $this->{CVer} = $1; + $this->{CId} = $2; + $this->{CSess} = $3; + $this->{State} = normal; + last; + }; + } +} + +sub change { + my($this, $msg) = @_; + $this->{FH}->print($msg); +} + +sub binary_input { + my($this, $data) = @_; + my $m = "_c_$this->{BC}"; + $this->{S}->$m($this,@{$this->{BP}}, $data); + print "REPLIEDBIN!\n"; + $this->{FH}->print("$this->{BCID} ok\n"); +} + + diff --git a/Perl/ZZPerlSimpleClient.pm b/Perl/ZZPerlSimpleClient.pm new file mode 100644 index 0000000..96b45ae --- /dev/null +++ b/Perl/ZZPerlSimpleClient.pm @@ -0,0 +1,111 @@ +# +# ZZPerlSimpleClient.pm +# +# Copyright (c) 1999, Tuomas Lukka +# +# You may use and distribute under the terms of either the GNU Lesser +# General Public License, either version 2 of the license or, +# at your choice, any later version. Alternatively, you may use and +# distribute under the terms of the XPL. +# +# See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# the licenses. +# +# This software 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 README +# file for more details. + + +# Provides the same routines as are inside the C++ scriptAPI for +# Perl, but using the remote interface. + +package ZZPerlSimpleClient; +use IO::Socket; +use base Exporter; +@EXPORT = qw/zzconnect get_cell new_cell delete_cell + connect_cells insert_cells insert_cell disconnect get_text + set_text/; + +my $socket; +my $reqno = 1; + +sub zzconnect { + my($hostport, $id) = @_; + $socket = IO::Socket::INET->new( + PeerAddr => $hostport, # host:port + Proto => tcp, + ) or die("No socket: $!"); + $socket->autoflush(1); + $init = <$socket>; + print "INI: $init\n"; + $socket->print("ZZ(0.03)($id)(1)\n"); +} +sub request { + my($req, $resp) = @_; + $reqno++; + $socket->print("$reqno $req"); + while(<$socket>) { + print "REP: $_\n"; + next unless s/^$reqno\s+//; + unless(/^$resp\b/) { + die("INVALID RESPONSE $_\n"); + } + if($resp eq "ok") { return } + if($resp eq "cellno") { + /^cellno\((.*?)\)/ or die("INV $_"); + return $1; + } + if($resp eq "text") { + /^text\((.*?)\)\((.*?)\)/ or die("INVT $_"); + my $nb = $2; + my $res; + my $b; + my $n; + my $cur; + while($nb > $n) { + $cur = read $socket, $b, $nb - $n; + if($cur == 0) { + die("NOR BYT"); + } + $n += $cur; + } + return $b; + } + } +} + +sub get_cell { + my($from, $dim, $dir) = @_; + return request("get($from)($dim)($dir)(0)(0)\n", "cellno"); +} +sub new_cell { + my($from, $dim, $dir) = @_; + return request("new($from)($dim)($dir)(0)(0)\n", "cellno"); +} +sub delete_cell { + my($cell) = @_; + request("delete($cell)", "ok"); +} +sub connect_cells { + my($from, $dim, $other) = @_; + return request("connect($from)($dim)($other)\n", "ok"); +} +sub insert_cell { + my($from, $dim, $dir, $other) = @_; + return request("connect($from)($dim)($dir)($other)\n", "ok"); +} +sub disconnect { + my($from, $dim, $dir) = @_; + return request("new($from)($dim)($dir)\n", "ok"); +} +sub get_text { + my($cell) = @_; + return request("gettext($cell)\n", "text"); +} +sub set_text { + my($cell, $t) = @_; + my $l = length $t; + return request("settext($cell)($l)\n$t", "ok"); +} + diff --git a/Perl/cperl.pl b/Perl/cperl.pl new file mode 100644 index 0000000..ed7611c --- /dev/null +++ b/Perl/cperl.pl @@ -0,0 +1,33 @@ +# +# cperl.pl +# +# Copyright (c) 1999, Tuomas Lukka +# +# You may use and distribute under the terms of either the GNU Lesser +# General Public License, either version 2 of the license or, +# at your choice, any later version. Alternatively, you may use and +# distribute under the terms of the XPL. +# +# See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# the licenses. +# +# This software 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 README +# file for more details. + + + +use lib "."; +use ZZPerlSimpleClient; +zzconnect('localhost:3546', foo); + +print get_text(1),"\n"; +$x = new_cell(1,"d.1", "+"); +$y = get_cell($x,"d.1", "-"); +$z = get_cell(1,"d.1", "+"); +print "GOT: '$x' '$y' '$z'\n"; +set_text($x,"FOOFOO"); + +print "DONE!\n"; + diff --git a/Perl/sperl.pl b/Perl/sperl.pl new file mode 100644 index 0000000..5e4a5ef --- /dev/null +++ b/Perl/sperl.pl @@ -0,0 +1,28 @@ +# +# sperl.pl +# +# Copyright (c) 1999, Tuomas Lukka +# +# You may use and distribute under the terms of either the GNU Lesser +# General Public License, either version 2 of the license or, +# at your choice, any later version. Alternatively, you may use and +# distribute under the terms of the XPL. +# +# See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# the licenses. +# +# This software 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 README +# file for more details. + + +use lib "."; +use ZZPerlDBServ; +use Event loop; + +$s = ZZPerlDBServ->new("S1",3546, "test.db"); + +print loop(); +print "OUT!\n"; +print $@; diff --git a/README b/README new file mode 100644 index 0000000..f1a01a9 --- /dev/null +++ b/README @@ -0,0 +1,65 @@ +gzigzag - an implementation of Ted Nelson's ZigZag structure +============================================================ + +NOTE!!! If you are wondering what to do, use the code in the +Java/ subdirectory. Go to the Java/ subdirectory and type 'make'. +If there are any problems, read Java/README. + +What is gzigzag ? +================= + +gzigzag is an implementation of the ZigZag(tm)* structure, which +was originally conceived by Ted Nelson. For more information about +ZigZag structure see Tuomas Lukka's 'A Gentle Introduction to Ted +Nelson's ZigZag Structure', which is included in the distribution as +Documentation/Gentle_Introduction. gzigzag was originally developed as a +student project in the Department of Mathematical Information Technology +at the University of Jyväskylä, Finland. + +It has been agreed that the gzigzag name and distribution are under +the care of Ted Nelson, and are currently maintained for him by the +Jyväskylä group. + +Directories +=========== + +Java/ -- Java version, standalone and network client. +Modules/ -- Various modules for the Java gzigzag +Documentation/ -- guess + +C++/ -- The C++ standalone clientserver. OLD, NOT USEFUL ANY MORE +Perl/ -- Perl code for network. NOT YET FUNCTIONAL + +Currently, the Java version is the one undergoing most development +and having the most functionality (much that is not found in the +C++ version). The C++ version has not been +touched since the last millennium and the Perl code is waiting +to be tested with the updated Java code (as a TCP/IP cellserver). + +License +======= + +You may use and distribute under the terms of either the GNU Lesser +General Public License, either version 2 of the license or, +at your choice, any later version. Alternatively, you may use and +distribute under the terms of the XPL. + +See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +the licenses. + + +Getting gzigzag +=============== + +The latest version of the gzigzag can be obtained through: + +http://gzigzag.sourceforge.net + +Compiling gzigzag +================= + +The individual directories have instructions regarding how to install +that version. + +------------------------------------------------------------------------------ +* ZigZag is the trademark of Ted Nelson, used with permission diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..8acdd82 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.0.1 diff --git a/changelog-authors b/changelog-authors new file mode 100644 index 0000000..7348054 --- /dev/null +++ b/changelog-authors @@ -0,0 +1,10 @@ +tjl:'Tuomas J. Lukka ' +veparkki:'Vesa Parkkinen ' +ajk:'Antti-Juhani Kaijanaho ' +tuukkah:'Tuukka Hastrup ' +bfallenstein:'Benjamin Fallenstein ' +cat:'Katariina Ervasti ' +deetsay:'Tero Mäyränen ' +otso:'Otso Kivekäs ' +raulir:'Rauli Ruohonen ' +wikikr:'Kimmo Wideroos ' diff --git a/cvsparser.pl b/cvsparser.pl new file mode 100644 index 0000000..7922fb2 --- /dev/null +++ b/cvsparser.pl @@ -0,0 +1,36 @@ +#!/usr/bin/perl -w +# Written by Antti-Juhani Kaijanaho for the GZigZag project + +use strict 'vars'; + +sub main { + my @dirs = (); + my $dn = ""; + push @dirs, "."; + DIRS : while ($#dirs >= 0) { + $dn = pop @dirs; + print STDERR "Finding files in `$dn'..."; + open(ENTRIES, "<$dn/CVS/Entries") || next DIRS; + while () { + if (m|^(D?)/([^/]+)/-?([0-9]+(\.[0-9]+)*)?/(dummy timestamp)?|) { + my $dir = ($1 eq "D"); + my $name = $2; + if (defined $5) { + print STDERR "Ignoring $name\n"; + } elsif ($dir) { + push @dirs, "$dn/$name"; + } else { + print "$dn/$name\n"; + } + } elsif (/^D$/) { + # ignore + } else { + print STDERR "###$_###"; + die "syntax error" + } + } + close(ENTRIES); + print STDERR "done.\n"; + } +} +main(); diff --git a/makedist.param b/makedist.param new file mode 100644 index 0000000..4c86928 --- /dev/null +++ b/makedist.param @@ -0,0 +1,2 @@ +# -*- Shell-script -*- +cvstree=yes diff --git a/makedist.sh b/makedist.sh new file mode 100644 index 0000000..f8ec7b7 --- /dev/null +++ b/makedist.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# makedist.sh +# * +# * You may use and distribute under the terms of either the GNU Lesser +# * General Public License, either version 2 of the license or, +# * at your choice, any later version. Alternatively, you may use and +# * distribute under the terms of the XPL. +# * +# * See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of +# * the licenses. +# * +# * This software 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 README +# * file for more details. +# * +# * Written by Antti-Juhani Kaijanaho + +set -e + +sign=no + +cont=true +while $cont +do + case "$1" in + -sign) sign=yes + shift ;; + *) cont=false ;; + esac +done + +srcdir=${2:-$(pwd)} +distdir=${1:-$(pwd)/gzigzag-dist} +rm -rf $distdir + +. makedist.param + +if [ "$cvstree" = "yes" ] +then + make Manifest +else + if [ ! -f Manifest ] + then + echo "Manifest is missing" + exit 1 + fi +fi + +for d in $((for f in $(cat Manifest) ; do dirname $f ; done) | sort | uniq) +do + echo -n "Making directory $distdir/$d ..." + mkdir -p $distdir/$d + echo "done." +done + +for f in $(cat Manifest) +do + echo -n "Copying $f ..." + ln $f $distdir/$f + echo "done." +done + +cat Manifest | xargs md5sum > $distdir/md5sum + +if [ "$sign" = "yes" ] +then + gpg --clearsign $distdir/md5sum + mv $distdir/md5sum.asc $distdir/md5sum +fi + + + diff --git a/manifest-filter.lst b/manifest-filter.lst new file mode 100644 index 0000000..4553fe4 --- /dev/null +++ b/manifest-filter.lst @@ -0,0 +1,4 @@ +- \.cvsignore +- Documentation/Manuscripts ++ Manifest +- src diff --git a/manifest-filter.pl b/manifest-filter.pl new file mode 100644 index 0000000..605361e --- /dev/null +++ b/manifest-filter.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + + +# +# Read in the filter list. +# Print out lines starting with + directly. +# Save the lines starting with - in the array @del for deleting +# the files from input later +# +open FILTER, ") { + /^\+ *(.*)$/ and print "$1\n"; + /^- *(.*)$/ and push @del, $1; +} + +# Loop through the standard input, deleting lines that match regexes +# in @del. +LINE: while (<>) { + for $f (@del) { + /$f/ and next LINE; + } + print; +} + diff --git a/md5sum b/md5sum new file mode 100644 index 0000000..5f1c86e --- /dev/null +++ b/md5sum @@ -0,0 +1,599 @@ +1cbf71f50938fd85bf9e2b2ebe5cc691 ./ChangeLog +5e70b82aec781fc9f7ef6190cb5906d5 ./changelog-authors +9eec46aa6edb26062c2a6a28c50e3359 ./ChangeLog.2000 +79edd7f18201f486d8814b9299e29198 ./CODING +dee9834caa1bf34f379a50a073d85b5e ./C++/README +1167e5b86ea1b0bb6be66a7a21e4494c ./cvsparser.pl +06922d1e5dc7926eb444f1a8ccb99560 ./Documentation/ApplitudeWriters/appw.wml +e82885b74c0c0217f278f349f342eea5 ./Documentation/ApplitudeWriters/Makefile +92acab08d20b603b3883c9105c885eaa ./Documentation/CellScroll/SCRATCH +2674320eed1ca8d1ef50accb4116acec ./Documentation/Clang_Design/design.ptex +2907639f2d97f13db5ad88afb8140f38 ./Documentation/Clang_Design/Makefile +8a5c0771131b1bf4184088a4043ce36c ./Documentation/Clang_Design/thales.wml +b214f82d1574f8fafa0625c24cb0ce2f ./Documentation/CyberText/ct-old.wml +1a150cba0b0c8b3dbc559d948e5ecfb7 ./Documentation/CyberText/ct.wml +1ae5dc076d7bdc489d14927c0bd8a879 ./Documentation/CyberText/email.dia +fbc5f4e1031a0af55183e5d89e509343 ./Documentation/CyberText/kello-o.png +90eb082375ffae5b09a0718d273185ec ./Documentation/CyberText/kello.png +3756d1682dc232ec019e7d3c41845b20 ./Documentation/CyberText/Makefile +e5bb2292dc8d678ef57be6175bda6b6c ./Documentation/CyberText/permascroll.dia +f4197bc6bb806d229bd139625bdb555b ./Documentation/CyberText/rank1vert.dia +c2cf6f505b8f9c575418434e8fe14111 ./Documentation/CyberText/rank2vert.dia +7c04ca907d86aee6b4a112c087c95e07 ./Documentation/CyberText/rank3both.dia +55c74e43e3c5de6b54326550c1022489 ./Documentation/CyberText/vilma.png +7d27e1fa281f318d1da7d7a42f5bd3af ./Documentation/CyberText/1.png +4be38eaa620b2e9c256a06092b9018e5 ./Documentation/CyberText/3.png +14afbae628da2fbaf6a1a3332b0037ae ./Documentation/CyberText/4.png +ad399fa4e7646fb604e443ca23b957b8 ./Documentation/DesignProblems/beamorder.dia +9f0f16b5b27f45a9cac3d770065c0854 ./Documentation/DesignProblems/dp.wml +1b7fb15e61a2a3628b96d58b0cb94cac ./Documentation/DesignProblems/linkorder.dia +12a4e5f5de692903d013ba6248129e23 ./Documentation/DesignProblems/Makefile +253bd65821ea9e18c29263c63d7a8772 ./Documentation/diagrams/cursoring.dia +9a0704f21e4d30f46481c1bfabcc9061 ./Documentation/diagrams/Makefile +5263347e542f5af9c5ac0aea9bb9f313 ./Documentation/diagrams/ZZCanvas.dia +e272690c0d831641cb946bd1e405347c ./Documentation/DimBased/dim.ptex +d77afb65c41a709df86322a0cab73f05 ./Documentation/DimBased/Makefile +b1ec5a66faee2d17eb995cba721168d8 ./Documentation/FAQ +79e5315e49c7c801cfea618cab18a353 ./Documentation/Gentle_Introduction/gi.wml +fefc1a337dc230ad29d29a5786434080 ./Documentation/Gentle_Introduction/Makefile +af0ee9f755f44804d8293294ed1e6f06 ./Documentation/Gentle_Introduction/README +93952985cf28fd78c67a5327733eb8e7 ./Documentation/Gentle_Introduction/zzgentle.tex +08e850bd71ecff403e5bb1180f54f182 ./Documentation/Glossary/gl.wml +4f873babe15b8f647d503b84b8fe6ea7 ./Documentation/Glossary/Makefile +5af65f3cc452571ce90b2c57c116e559 ./Documentation/index.html +3b9c62c919a9d5bab2f6d5b2499cc637 ./Documentation/Interfacing/int.ptex +2d18881f757b5e977946d566969c6e96 ./Documentation/Interfacing/Makefile +75850a3d3febe8f743e9b163849a0f15 ./Documentation/keybindings.wml +0f164425af5921445fe00f7b2b6642c1 ./Documentation/lib.mk +d260d145647e25194097a4b1210760af ./Documentation/Makefile +f1a59137ce45b80e08ce6bda3a53ec9f ./Documentation/Math/ajk-scribbles.tex +4f10758373d972db6de55a236dcc40fe ./Documentation/Math/Makefile +58b2455932f29eaf1c72e2a722812d75 ./Documentation/Math/math.ptex +ca6f9c8b6fd7c8b006583f00668d531a ./Documentation/Mediaserver/mediaserver.tex +f38eaf3ab7540eebc48feda5366b62d0 ./Documentation/misc/ADDRESSING +7c3e8882a776e349639623c201df4168 ./Documentation/misc/billow +636a76d80d6d5dea56be29a414c89937 ./Documentation/misc/byrokratiadoku +e0c64f493dc191af2c1caae5fe7b7e68 ./Documentation/misc/Curseling +8b2139061a39e136df30723f73bb9bd8 ./Documentation/misc/keys +265d31082a50876994efdaa16d146c98 ./Documentation/misc/RENDERING +0f3754f0ed3338d7fcf6989092a0c77c ./Documentation/misc/textcloud +06145b9937d60e2552eb013b33e613ee ./Documentation/misc/TORESOLVE +1c7f94813f247924c7623d2bc014e8ca ./Documentation/Networking/Makefile +568c9cded573b264bbb0e24d8b3a4481 ./Documentation/Networking/mock-ZTPTCP.txt +d0fec04278f67fc36bba96e234ccafb0 ./Documentation/Networking/ZTP.txt +9d16f6e6c75c26ada809c16a8596f25b ./Documentation/Networking/ZTP-usage.txt +296fe725d3651b14292c6a28a7054d5a ./Documentation/Networking/ztp.wml +77dddfa14c58042df82a266c129b2515 ./Documentation/Nile/Makefile +272da468da76e3962c356d7824cbc22c ./Documentation/Nile/nileug.wml +b4c56dffdb28382cbd76ca17b5c5cc82 ./Documentation/Nile/nile.wml +3df296abc1207cf955a4ad4fd0747920 ./Documentation/PROTOCOL +320d3e5c4fcbc755c5c225d587512271 ./Documentation/README +f7e97d4ded8f11077d4042f6c688a012 ./Documentation/Slices/SliceLogic +ad55238dfcf895470e7df47d6cca7117 ./Documentation/Slices/zzSliceLogic.jpg +5751d534620a7b4798abf208818d2d44 ./Documentation/Spec/canvasraster.dia +3b423006824e0aecb10fb1ee69530110 ./Documentation/Spec/cursordim.dia +76d41ccc440b56a52350e31ea96ac2e6 ./Documentation/Spec/cursor1.dia +52be0a8acb7c050480f16fdc2f4434b4 ./Documentation/Spec/email1.dia +92982cd98f6a838e165fbc42d4193a21 ./Documentation/Spec/inheritparam.dia +a2930af8d526a78068dac25cdf39f2d7 ./Documentation/Spec/Makefile +2878d8156b13f608a0eb3f8c914e6c4d ./Documentation/Spec/rasterspec.dia +60b4837514ac1ce687603f95afd86bb2 ./Documentation/Spec/zzspec.wml +3b673f36c676d5e6e7ed272582f8dd42 ./Documentation/STARTING +deb9f5fb94f26dbe14ec359f56932f14 ./Documentation/Syntaxless/synt.wml +f29ac786d3105c04f90ba9568e73e044 ./Documentation/UsersGuide/active.png +c33a80abab73e9e71379adafb252c1a1 ./Documentation/UsersGuide/addressbook.png +784d854d26524ebff1cedc1dc3937c1a ./Documentation/UsersGuide/aftermove.png +ac959b546e01c99afe44ebca28495853 ./Documentation/UsersGuide/alku.png +f274fa4f95834c9e69393f31538af4ae ./Documentation/UsersGuide/bind1.png +6e76a6570fc6a6272334398f93dc8130 ./Documentation/UsersGuide/bind2.png +8bc6cef14abcff76b3a49b084cc5c519 ./Documentation/UsersGuide/boring.png +8569479426c6c89f05c0b231aaca973b ./Documentation/UsersGuide/bothwins.png +165248dc62dcbae10b38c84c1de48dd3 ./Documentation/UsersGuide/breakkafka.png +2861f3af6c607b00baf1dc39a39458e6 ./Documentation/UsersGuide/change1.png +adc2e98476d2b2ce970d6ea7d3cd2a68 ./Documentation/UsersGuide/change2.png +c6455d9d3f0d84c7102790658556a15f ./Documentation/UsersGuide/child1.png +800fdf10d240fef7fc5dd5a19b20dc6c ./Documentation/UsersGuide/child2.png +a08558f901d4f0c17b13835d5b0c58d1 ./Documentation/UsersGuide/clone1.png +927cde9403515d7e2087eb849e74ad47 ./Documentation/UsersGuide/clone2.png +89ed97b2dc2735684351e461ac6c2e4f ./Documentation/UsersGuide/connection1.png +8a00b7affd55a7624c779bbbf92ccbec ./Documentation/UsersGuide/connect1.png +8792ac4e6399067f954acb417e9a27c3 ./Documentation/UsersGuide/connect2.png +a5663428ef55d8cc385b73eada991464 ./Documentation/UsersGuide/creation.png +5538144f60b3d606ea4c59eaf24e6bc3 ./Documentation/UsersGuide/dimensio.png +03a2e7f760605fec73573fca9741c250 ./Documentation/UsersGuide/edit1.png +79febd4cf0fd79c8cef3b299f8e69fa9 ./Documentation/UsersGuide/edit2.png +686d0a00044ef7de7f3b4afd7e29ca8c ./Documentation/UsersGuide/edit3.png +9fd330f680ed8bc8ec4b5b746863965e ./Documentation/UsersGuide/edit4.png +350c00c89788bddbc9f23ab4d1d01b80 ./Documentation/UsersGuide/extra.png +94c8c1331a4e4f48dab5f42c8c8ed60e ./Documentation/UsersGuide/familytree.png +a4ba8b5afeda337b46e413fe9452c928 ./Documentation/UsersGuide/font.png +548c53363088e18b477197b853c70702 ./Documentation/UsersGuide/f2.png +723a4abb4e5cf218a0f2620c28c331f3 ./Documentation/UsersGuide/grey.png +3c09feb17c60f73a83ea737ba407c3d5 ./Documentation/UsersGuide/hopolympos.png +0d7443fe6b900ca6a660e7c0ead162f7 ./Documentation/UsersGuide/hop1.png +32c296d606aed817bc844cb5c7e2edb0 ./Documentation/UsersGuide/hop2.png +ee91d3c8f7933a0f95fc2ded1d0564e0 ./Documentation/UsersGuide/htree.png +4137cd14f3b73722b79fcae29931a7f9 ./Documentation/UsersGuide/kafka.png +e2c5ff9c557816c811e5a0be5c7dfbba ./Documentation/UsersGuide/klooni.png +75778d9754af31df5197ec52d8f4f845 ./Documentation/UsersGuide/Makefile +2c9d93eac5e5512174fd432eedc92543 ./Documentation/UsersGuide/make1.png +12f4651c7be12d85f35ef8b19de9d9ae ./Documentation/UsersGuide/make2.png +6d4bab0a69e186b10150bb3dcf05023b ./Documentation/UsersGuide/make3.png +a69f1217f07921e34f0e83c518ca8250 ./Documentation/UsersGuide/make4.png +8618217b75529fbe05e356082cba2d41 ./Documentation/UsersGuide/make5.png +13b95a23fcb0966086311bce3c0cd26a ./Documentation/UsersGuide/make6.png +7531ee4cc6b04fc9b36daaf78c288f8e ./Documentation/UsersGuide/margins.png +3c67cd490eaf1c649d783efae7ec835f ./Documentation/UsersGuide/markconnect.png +130e67557d777cd038ab7ef375223e01 ./Documentation/UsersGuide/mark1.png +490f75b9c2ed33fcc380db7b0e9e76c7 ./Documentation/UsersGuide/mark2.png +08f121f59d3edbe1901764bd49f55ce7 ./Documentation/UsersGuide/mutsiosoite.png +c2b954b41415d45cd59c894ad02a8969 ./Documentation/UsersGuide/mutsi.png +2e4e0784ca64841555048f2699252d69 ./Documentation/UsersGuide/myspeech.png +72e636c5d1d4f7ef7be589de4fbc5e72 ./Documentation/UsersGuide/myspeech1.png +1b3f0ba2c3cccbb31038a31c24b68591 ./Documentation/UsersGuide/myspeech2.png +b3048fece5fa01d40c20df6aa7b07e2f ./Documentation/UsersGuide/myspeech3.png +4949ff33daad35f3f63904404f118008 ./Documentation/UsersGuide/newcells.png +1a483e3e87f2b4c8c6cf5296c7222a99 ./Documentation/UsersGuide/newstory.png +89be29789e3aaa86f58351b4b0964feb ./Documentation/UsersGuide/newstory2.png +98a1c77312d2e9d9375ad3849ffa1f12 ./Documentation/UsersGuide/newstory3.png +05d976c5ca5fbd03bf1309c0903878dd ./Documentation/UsersGuide/newug.wml +aa819e5c0cdd837b2a6ee26775805215 ./Documentation/UsersGuide/olympos.png +207140cf3d14a4c7a9fe903875ebf15e ./Documentation/UsersGuide/olympos2.png +66546455337c689d372bde846ff4c450 ./Documentation/UsersGuide/osoite.png +6670ec3ee81424a5d40290d70d9d6d8b ./Documentation/UsersGuide/para.png +6b5dfe2bc462ceb8f125d51e577f2af9 ./Documentation/UsersGuide/rainy.png +982c903248bafde07abb4b3f0111dc75 ./Documentation/UsersGuide/rastererror.png +ef92db0ce3c1d923f617bbb7571b5292 ./Documentation/UsersGuide/rcfact1.png +b89d3fbf91d149e186d1c82c96d5ecec ./Documentation/UsersGuide/rightmoved.png +4c1407664c7d38cb3910522426c111de ./Documentation/UsersGuide/rotate.png +3dff900f0f6cfa4aaeff508cd143eaf7 ./Documentation/UsersGuide/row.png +737367b98fcd2f1c8f09dfd38f9c6917 ./Documentation/UsersGuide/shinyhappy.png +9d0a435240db859fcec0deacbc59a7f9 ./Documentation/UsersGuide/shinyhappy2.png +7fabbee9c8b9cf277de04cdb2d20c639 ./Documentation/UsersGuide/shinyhappy3.png +10ed552a5d23a84f84a3cc77f7226497 ./Documentation/UsersGuide/shiny.png +85feda8e083bf39b31cac764618f3fc7 ./Documentation/UsersGuide/showingz.png +8026e9597dbb58407c2414d2e4e38094 ./Documentation/UsersGuide/start.png +5af1ce5db874152e57edf32125a35bbd ./Documentation/UsersGuide/story.png +02184d8e5aa7005de8424cda5d3245c8 ./Documentation/UsersGuide/storytext.png +e352a9c06afb8efa60f2adb587f6aed7 ./Documentation/UsersGuide/structure1.png +bf8565b0a2c0527c492b216477b1148d ./Documentation/UsersGuide/structure2.png +e2e5105de48ce3d80b0cc24a703afdca ./Documentation/UsersGuide/suku.png +3747471bb345f26ed3ea350c4b326511 ./Documentation/UsersGuide/testi.png +8d43b85a0508199a1278de2c1f33b2d3 ./Documentation/UsersGuide/ug.wml +1efbea4c1234c467bdbebfe89e159107 ./Documentation/UsersGuide/wallstreet.png +ee009a5faf5915cf29de63dee8410e82 ./Documentation/UsersGuide/widthstr.png +68eb90f0a5ab638acbc25b439e9994f3 ./Documentation/UsersGuide/wrongconn.png +468ab82ce27c8494d30ca0c1131d6e6c ./Documentation/wmlinc/art.css +9ffdb9946a33e224adf25d5d0ff91f08 ./Documentation/wmlinc/article.wml +c12776714f82acad6e02a1f695aad4f4 ./Documentation/wmlinc/catart.wml +955b7704c6a83a896f72b5fa90469b03 ./Documentation/wmlinc/common.wml +cbb1c89ee6d808f74f34ec2f161d433d ./INSTALL +6fcebaf4cd4ffe29a347f092bfc8e8f6 ./Java/ApplitudeMgr.java +8d4ff2ac9cc7d9fa3101f21160f9df5b ./Java/arch/javadoc/ZobDoc.java +c3fb86ba30675a643cd95d7d7b81ac71 ./Java/arch/java2d/ZZDrawingJ2D.java +5cceb6acbb2ef051e24247acf71fea35 ./Java/arch/syslog/arch.mk +dbe724cf87045aadc7b5e2511cf0679e ./Java/arch/syslog/org_gzigzag_SysLogger.c +5618cad8358b1cc3c6a74ff70f97b65b ./Java/BuildInfo.java.in +352f9bb095e968e988bb8eb498b85a8b ./Java/check.pl +7ac606745c75a928701064a8c0ff97c7 ./Java/ChkVersion.java +0a170b4bd8c299d0149767fcb27d8801 ./Java/clang/Data.java +e6d1ba4953e0786e051901ea6cc52bd2 ./Java/clang/flowing/B.java +be9302493189fb8442ded02c8ad61801 ./Java/clang/flowing/C.java +2fcfe2c4d43f66bdc3b2ec251034d221 ./Java/clang/flowing/FlowingClang.java +60214e087486f753bdf9c93499d20139 ./Java/clang/flowing/Flowing.java +f800f1c59d453cda75d78bd70462e880 ./Java/clang/flowing/Primitive.java +3c5e54b2b06b20ccffb7dddf2aef1d3e ./Java/clang/flowing/PrimitiveSet.java +d31c18fab0d54bdd4a6113c04e3462d4 ./Java/clang/flowing/StackFrame.java +44756aa8af6df7312c5dde10562a0256 ./Java/clang/flowing/StackFrameReal.java +09395dd9093976eff1c8d45d42b3c0ae ./Java/clang/flowing/StackFrameVirtual.java +f934cc2c108e2fa2d61422e855289db1 ./Java/clang/flowing/T.java +fa2e1d27fa6babbe34de14ad149eaa7d ./Java/clang/flowing/X.java +aaa3f5cc5b4f74a6cfa174db006743bd ./Java/clang/heraclitus/HeraclitusClang.java +d276e10a983aefd598648d64641a7e5f ./Java/clang/heraclitus/HeraclitusCommand.zob +1a3899708d7cc5bef3dbb074b367b04b ./Java/clang/heraclitus/Primitive.java +0afff042ad311d2e839a319d900bbcb1 ./Java/clang/heraclitus/PrimitiveSet.java +9a672efeabe43c6c890783a8a2b2343e ./Java/clang/heraclitus/PS1.java +e8a13b7342c8e9cad0b75d5dc2d31b0b ./Java/clang/thales/DimensionNames.java +371d510a88848efb11959ece7ad98b65 ./Java/clang/thales/Environment.java +128be976b5de6f553d6c37c654b3b100 ./Java/clang/thales/Evaluator.java +e8e230f3b73782480eb291751af30ea4 ./Java/clang/thales/PrimitiveOperation.java +ee3a15acb9ac3259fb2bfc2fd5cb24b6 ./Java/clang/thales/primitives/If.java +9bfe3f683440814ee87f68a120972d19 ./Java/clang/thales/README +8b1c48cc67f6fc4a355184aeca1074d0 ./Java/clang/thales/Refcounted.java +9c9cc69252cdd1ea5bbd7e145d08d657 ./Java/clang/thales/SyntaxForm.java +c6c17b6d21fb8aa256a862ba181f8a7a ./Java/clang/thales/syntaxforms/Abstraction.java +609d3b490a144b5e73e082c91039aff8 ./Java/clang/thales/syntaxforms/CellDenoter.java +07018b35a1780bc64df209c537e449dd ./Java/clang/thales/syntaxforms/CellLiteral.java +9c96b45a321a6be5e54e147a9e118b1c ./Java/clang/thales/syntaxforms/Primitive.java +9cd91778072b0a73790ee3f33084d935 ./Java/clang/thales/syntaxforms/Sequence.java +3f7914ffff5d65bc8ae769454565ce14 ./Java/clang/thales/Task.java +d0670191a618407de5daacd31715d913 ./Java/clang/thales/ThalesClang.java +00d9f6e0dde985bc7b5aa6572bf4b17e ./Java/clang/thales/ThalesProgram.zob +520276baf1b487178a86d9e4352ba9be ./Java/clang/ZZClangContext.java +ba5a6f3ee5be3c25edace6f2f40d13d9 ./Java/clang/ZZClangContextReal.java +c5873ec335d6eaa7bc1f87d41940c73a ./Java/clang/ZZClangContextVirtual.java +7a208dd269adc33efebf39cbb0b5559b ./Java/clang/ZZClangOp.java +68bcde9d6781d3fabd938659b1b11454 ./Java/clang/ZZClangOps.pl +fcbd4f896f500fad141d031bef7e3fbe ./Java/clang/ZZClang1.java +2744012f6cf00b2617724d4c4576b667 ./Java/CommandLineOptionsParser.java +c7de291e516bb432b22b57f9917ddb44 ./Java/d.java +a1e99e31ab9d419b170a0559f6aba403 ./Java/Dumper.java +21b87b81daed7c7e623455c3a6c9504c ./Java/Dump.java +a46e0d74248efe5d4336d6d79790b548 ./Java/dump2java.pl +8c985388765d50de623da830ff5c2bed ./Java/errors/MissingTermError.java +9116e5fb34b9cfc04218406bb984dd79 ./Java/errors/SyntaxError.java +1beeb7fc4c2760bc93e0421f0bf269ce ./Java/errors/ZZConnectWouldBreakError.java +086e1a7071cf89df15433cbb62e72c4c ./Java/errors/ZZError.java +73b0b664900a6b0aaae2efe0d5759c46 ./Java/errors/ZZFatalError.java +324d7097b22bbb700b62668fdfe1212e ./Java/errors/ZZInfiniteLoop.java +4254f59ca80aa334d2a2006a9cf939ee ./Java/errors/ZZInvalidCursorPositionError.java +c9b1b4c3601bd940435e281204cab946 ./Java/errors/ZZInvalidDimensionError.java +189e443c496591fc676cacd2cca93484 ./Java/exp/rast/vanishing.view +829fe293f2b0391bc43bdade843ee2d6 ./Java/flob/ArrowDecor.java +479f203e477234f64e9bc7dee029a4f2 ./Java/flob/BallCell.java +23bdd09339027f43f3b5031ac80dbf5c ./Java/flob/BeamDecor.java +040949a70c63a2b44ac3893026b62d75 ./Java/flob/BoxedFlob.java +2bac9ea9f7236674ea1f8e736630668e ./Java/flob/BoxType.java +60cf44f339bb502363a6b9a052ba72ee ./Java/flob/CellBgFlob.java +31caa624e77cd73bfc7b8bfe6d9d2081 ./Java/flob/CellFlobFactory1.zob +1cd48783b5418d783acc16c45b9078fc ./Java/flob/CellFlobFactory2.zob +83bad85795c37f85a312ac5dee3cf0d2 ./Java/flob/CellFlob1.java +697625ee706d6737e2b29419c9027ddd ./Java/flob/Colorer.java +1f9f90195bb4de5f240889176d762a6b ./Java/flob/CombinedView.zob +c3dc191cf65beb72990320aca8aa53f6 ./Java/flob/CompassView.zob +9a9d96c9dc565a8753381ac5879f1a4f ./Java/flob/ConnectionLineDecor.java +d71fa969f2b5df41fc913e5c3e07f5e8 ./Java/flob/CoordDecor.java +71e8c9f5546a6bf5ef790b87622a0cce ./Java/flob/CursorView.zob +e672105c03169bb4842a232d0ae80878 ./Java/flob/FlobDecorator.java +277ce61142bc645b76c8edf2522cb6dd ./Java/flob/FlobFactory.java +a969a14677160aac3e294f14f2b64354 ./Java/flob/Flob.java +98e5da013eefd07751010195f289b8a4 ./Java/flob/FlobSet.java +d74ba6956d8325232a96ae87af259d62 ./Java/flob/FlobView.java +234bf33239ef847d729939936bf110bc ./Java/flob/FTextCellView.zob +e2d83c5add5898199a326acea42f895d ./Java/flob/FTextLayouter.zob +05e2f43f5f69c8e4a3710ed8ebdcb0da ./Java/flob/GridGeom.java +545a6f78cf5a842169802bccbc16a71f ./Java/flob/ICView.zob +db664d3c85a08e506f2bc30826250df5 ./Java/flob/IdiosyncraticFlobFactory.zob +66b04915ad7a040c396d778af536efcc ./Java/flob/Level.java +54b1e8d489c6a8829b34dd943af17bfd ./Java/flob/LevelView.zob +29ec3ece03132c0a38d4e7dc82f8f5fd ./Java/flob/LineDecor.java +aad17c88f924778964702865a3cc479c ./Java/flob/MagGrid.zob +47eef925a2b406050c3381f3c48edf6b ./Java/flob/ManyToManyView.zob +dbd055860be4bcc907cd23785ef48891 ./Java/flob/MultiView.zob +f706340dda0ac0060d9bf00fdf222559 ./Java/flob/NullView.zob +8f943756074e0240be2ef4da2fb1c6ca ./Java/flob/ParallelTextView.zob +196dae163d44f45d2170cdeceb33c054 ./Java/flob/RankTextView.zob +e5315a9e83ef724f42bf5eff867f181d ./Java/flob/Renderable.java +312643ece8285bf6cfae3b59059bfb33 ./Java/flob/RowColView.zob +1cf8f4beb8ccd21cd5439206ea196e18 ./Java/flob/SceneFlob.java +33afff7c641b2bfbd108776082958fb3 ./Java/flob/SimpleBeamer.zob +5eeed6179c4548506758cc8256e096a4 ./Java/flob/SimpleBoxType.java +d0f17cdd840fe89ae95d2d97105400f0 ./Java/flob/SimpleFlobConnector.zob +ad64f69aec2423e6ceb62beb5ae2235f ./Java/flob/SimpleFlobView.zob +5e38f1d3ad4c271ecd8320a39ba96f41 ./Java/flob/SimpleSceneFlob.java +9290115001078986cc48a97aa40e6176 ./Java/flob/SimpleTextView.zob +01941c9b135f3032c29bdc2c167475af ./Java/flob/SpanFlob.java +e13dbee183befe6d8ea8db08025473e9 ./Java/flob/SplitCellFlob1.java +0888f6cf53e538a333cca7e184a03a3c ./Java/flob/SplitView.zob +9b9a8146fd77d1b1ede78c21c16402ac ./Java/flob/StdLinks.zob +064fee912247d9731e3986f7a20f0213 ./Java/flob/TextDecor.java +ac6beebe1fb02317c9799508248a3a71 ./Java/flob/TreeView.zob +38714eeb30421f9b703d00585b865afb ./Java/flob/VanishingView.zob +88cde6505b0a764dc7e920b8fc59a419 ./Java/flob/VobSet.java +54f80679d7bbdf7ea9b2cdb97c5d6afc ./Java/flob/WindowCellView.zob +4c3146285128a9e236723acb1eeb2646 ./Java/.gvimrc +42dfb0d169a939e003338dac39bc1e9c ./Java/JEv.java +5bd534e4d0ce9278e3c438e0234befc5 ./Java/LoopDetector.java +03fea609420a2d5722098c7b8c5279e9 ./Java/Main.java +f24687e2f2f52dfdcbae9b262be4a101 ./Java/Makefile +c75150ee9cb573df9580deca284cd7cc ./Java/media/Address.java +b2798df6ed30ef0bffb07af9d87d1257 ./Java/media/ByteScroll.java +33bcff0d04071eb6283741f663e9d537 ./Java/media/Capitalizer.java +06de2b7c32c816b406717b06fc86b04e ./Java/media/CharScroll.java +68fef86c239386db3bdab433b1d470b1 ./Java/media/FirstMatchBreaker.java +088f112c627fa574688610469615d5c0 ./Java/media/FText.java +3ae2766b21730781a96504dbe925e6c6 ./Java/media/LineBreaker.java +9515c7ee596939173625d59189af8141 ./Java/media/LineInfo.java +559de5d34663437a9d99edcfbcf01e19 ./Java/media/README +572668768fe57e8d200f1ae1698b84d6 ./Java/media/Scroll.java +7ddfd81401ac8d9a9256217a66f8298d ./Java/media/SimpleLineBreaker.java +38837807006dcc3f143e9c667f284f7e ./Java/media/SimpleLineInfo.java +d494a948d30c8d0aa561a878cd8e5c59 ./Java/media/SoundScroll.java +7e1f2958322ba496318b737a4fb83a5e ./Java/media/Span.java +755e10f2f2ec735ca99b65ff4bb2a9b2 ./Java/media/SpanSet.java +debc580f87e4f3280aa4b8e33c4ebf65 ./Java/media/SpanTree.java +e36c7f6f0a412741c0bfd6fbe78952b0 ./Java/media/Stream.java +51e5c7a99ea1e5ba68a9762f1dd6aab5 ./Java/media/StringScroll.java +879998e4bc07e2c8294bb89c6bd11e60 ./Java/media/TestLines.java +488763ed1902ab41eb863f2e6825d2dc ./Java/media/UTF8Char.java +b3b9ce84c5135294f02a8d191a23f442 ./Java/media/VStream.java +16adf9791d30c197e3b72fc46a1183a7 ./Java/media/ZZDefaultText.java +1e69024890ca5b387c989b03a20a20fd ./Java/media/ZZHumber.java +90e968f0791ce180b747222d5ab0ff10 ./Java/media/ZZSoundView.java +2b4dd4d16f5890db2d5a9f0f2b127674 ./Java/media/ZZText.java +faa7fad7fc880e4a69719d2b8859e87e ./Java/mungencss.pl +90d88252a16f98cadccfa14131dc157a ./Java/net/Peer.java +bfb767cb48d2643b133fb5d8e7e812e7 ./Java/net/ReliableUDPMessageFactory.java +9fe1038cd501a815497982fdf59206b9 ./Java/net/ReliableUDPMessage.java +75c21c58acaa278f86a542dacd31d9c6 ./Java/net/ReliableUDPSocket.java +c5a9fb1d8ef674df0c4b1ac35d85cfc2 ./Java/NullZOb.java +101219d5c50d07396356ec636de1bc5c ./Java/Package.html +c6b804589491b0197e623628de43c058 ./Java/part/BinaryTreePart.java +9c9a918d455806ca0fe70953e18f2c8f ./Java/part/DoubleStepPart.java +3d89637aff17f2026c4d7aa4fb9a3f2b ./Java/part/GenTreePart.java +c2e29c3ab9a48f298e8cb337daea8c1f ./Java/part/GenTreePartModel.java +71a810834cdaca798ee534741a279850 ./Java/part/GenTreeTestModel.java +afb53e36dfe913c67155a360920fe8ba ./Java/part/ImpliedTreePart.java +59e01fb7fb001b1d9c5c889a2a48979f ./Java/part/ImpliedTreePart2.java +6290103738e7e0aa407b652bb214cb63 ./Java/part/VersionPart.java +fe359a75105ba97b60db0a8b56fd7c7e ./Java/part/ZZROSpacePart.java +9fbc1c57b64c362a2e07719b0cd58d80 ./Java/part/ZZROStrSpacePart.java +1cfbabf626a85eaecb270da98621f450 ./Java/p2p/P2PStorage.java +6f0f36a24800a5901bfa7d63d223c1ea ./Java/p2p/UniqueID.java +5192d88653fa70415b83ecb49fadd7ff ./Java/README +c51cab2867beb87854eb83884daea16b ./Java/RString.java +8281b907c346e9d20d7537caee8a7b45 ./Java/SafeExit.java +1b2f9f2d866fa9ae6d37bbc8f709ee0b ./Java/ScalableFont.java +1be0e6a0b504d4d50feebeec19413615 ./Java/script/invoke.c +5299eb4a9ecb9456746b1b9cf21fc582 ./Java/script/Makefile +23c8c2d4a061afd4f210cfa2e885b29e ./Java/script/ZZId.h +6c461c6180710bf4377dc08b624a5103 ./Java/script/ZZScriptAPI_1_JNI.cpp +42cd737f20462535217e80c2db2aab49 ./Java/script/ZZScriptAPI_1_JNI.h +de5a57abfd0f0865dfbf4abe5e883e5b ./Java/script/ZZScriptPerl.cpp +0fdd0f793a4cc21c36ca38ae06be8919 ./Java/script/ZZScriptPerl.java +7f2f3f17df2d393ee9cb5657b03b5809 ./Java/SoundObs.java +a9c4b297676533c9f028165a6fca0226 ./Java/SpaceDump.java +20b9a4285a76a5a848f61ba9a0912c7e ./Java/storage/ContentStore.java +2e6919f346b024c01318c36fedf07d64 ./Java/storage/ContentStorer.java +cf4f9f42d8733e026286cfbc9d97d3f0 ./Java/storage/CountingStream.java +626f2817e1c42042239e879c677bfd8e ./Java/storage/DimStore.java +705ac5783262f04715aa702d348982db ./Java/storage/DirStreamSet.java +efe67476d4de323f667360c6f60b5d83 ./Java/storage/DummyStreamSet.java +983c3a6299ed47fce17d435eeb918a89 ./Java/storage/FileWritable.java +7aa6afc88dad9e3b4298eabf887a0213 ./Java/storage/Flushable.java +58506f32ddb5d7990af0d0718cc5f7e5 ./Java/storage/GZZ0.java +8e234262643385d2e2323109d779a528 ./Java/storage/MemWritable.java +33665cf2ea61206d7037daa025c480d7 ./Java/storage/Recs.pl +2ab5f8ec20b18703c20d9334faf61c83 ./Java/storage/SimpleContentFile.java +a6ff3b41a8af895114f5708244f8046a ./Java/storage/SimpleDimFile.java +52225a2559c249525da2e8bff3feebd5 ./Java/storage/SlicedCursor.java +c7ee3fa988dcc3268ca341e2db74c939 ./Java/storage/SlicedHomes.java +c5ad93ecfb8fd5688db1900fc6a1b287 ./Java/storage/Sliced.java +0f8490c364121d1370a8c6049d0380d8 ./Java/storage/SlicedSame.java +6f4978f3740a5b643116875934d99062 ./Java/storage/StreamSet.java +70486a4938fe8cc0f561bc9aab4bfa90 ./Java/storage/Writable.java +cf6e5d83669af794e0f720130c67401b ./Java/storage/ZZCacheContentStore.java +65e6a431b87d15da43a6a130dbe54350 ./Java/storage/ZZCacheDimension.java +84e54d49956c272a9d7261303fd0b23d ./Java/storage/ZZCacheDimSpace.java +90dc1b748866de7e217f126e237aad98 ./Java/storage/ZZDimStorer.java +24321864c1953cecbf651628ce1b1c82 ./Java/SysLogger.java +2a543bd95033b72d250521d8e69f4f97 ./Java/TestSpace.java +e41d64d35f1a6e72bc4a86f5d28b896f ./Java/TimeTest.java +212266fe772063ec572a7379355a7805 ./Java/TODO +1daf7016dd4c9a9db8551fa21e7b18ac ./Java/transform/ChangeDim.java +9baae4ba62744ce2da84dd2b05b4464b ./Java/transform/ClearDim.java +c63a14783b65d1d8fae7cbb646667a17 ./Java/transform/CopyDim.java +2afae00f73d9bef80df626280bc718e7 ./Java/transform/FoldDim.java +88e34fb3456366afc52c07b0d25254cf ./Java/transform/ReverseDim.java +7111804cbdb7ec2c90d848a9eaaf35ef ./Java/transform/VersionChanger.java +56b47bbb0af60699cbe5318ff6c9e0ae ./Java/transform/Version0.java +b689899172de4a0fcf8fac061eeba416 ./Java/transform/Version1.java +de320303cb8e4061e37fe9be0802a33d ./Java/transform/Version2.java +48e67d0bf0c9eac3888f26c27d9a91af ./Java/UndoList.java +52faf2b849eb16c46820babe76156b86 ./Java/ZOb.java +020bb3094e861cf4f3baff92bd97ad06 ./Java/zob2java.pl +532a18ff07255253425feaaac6729488 ./Java/ZTPCommand.java +7fc7fbc6ec94a933208040b0df4501c9 ./Java/ZZCanvasView.java +9ce7c4325d83f61ebcde31c9be4d3678 ./Java/ZZCellHandle.java +eba55ed2c72c8c0f167fc36341a0f3df ./Java/ZZCell.java +d0a8062146a83dfa72fd122850e093f5 ./Java/ZZCommand.java +f57f611b48cef525343946bbf7bf3089 ./Java/ZZConnection.java +043c7d81f28215210ed0b640c9297bcc ./Java/ZZCursor.java +2364cfd0d379f8feb451c8e11585e8b0 ./Java/ZZCursorReal.java +acb09e456ae4928b8e3d247dfd43bff4 ./Java/ZZCursorVirtual.java +7db8701915cab0b9b8dc166dff0a095d ./Java/ZZDefaultSpace.java +e72a512f1dcff0c3fe29e980d6faf3b4 ./Java/ZZDimension.java +89891888fb9554460177dd0047a3f36f ./Java/ZZDimSpace.java +af212418ec060449f20adcc6c012164d ./Java/ZZDrawing.java +ac07bff3aad3e2af70d1bb0e5881afee ./Java/ZZEvObs.java +57efea7e3addacc684612a72ae7b0340 ./Java/ZZExec.java +3715ccb7690a50282c2e77c02df45537 ./Java/ZZIter.java +4b4105e5420fe89b6db60a71da4bc5a5 ./Java/ZZKeyBindings.java +bfcaa696d3afcdef802de0b59164ecea ./Java/ZZKeyBindings0.java +d783dcd54fa3e61a888f4e609b54c119 ./Java/ZZKeyBindings1.java +269c22b51cc783ec4407d99b418baeb4 ./Java/ZZKeyHacks.java +a671c87ee71506e70bd1bf537e2976ac ./Java/ZZLocalDimension.java +8feb87db44092ffce2197b30e369a6fd ./Java/ZZLogger.java +12597e0332c5330c371645e1529c1952 ./Java/ZZModule.java +40a98c7bee5f339674822c0c269f8f4d ./Java/ZZObs.java +8a144980a5b8b6d94cb9b38470d73d71 ./Java/ZZObsTrigger.java +217b252092dbba0940919cfa7b2de264 ./Java/ZZPath.java +920dfcc9b460a80c523b7a639dd29a4e ./Java/ZZPhotoView.java +9a1d00c3123361ca031a08f7a0e355b8 ./Java/ZZPrimitiveActions.java +9f4e93522dcc7ee8656093ba59f4daca ./Java/ZZPrimitiveCommand.zob +b668abe45f13613ddd506ab07becaf55 ./Java/ZZRODimension.java +7735ba74206e1c2ce3b2b7fec20ab8e2 ./Java/ZZScene.java +32deb6719f25e084a564af870e3b196e ./Java/ZZSlicedDimSpace.java +8529bd5dea9b7c452ec62c0e739e84f4 ./Java/ZZSpace.java +43b97e57ec39bc7dcc308ee1b699c6ee ./Java/ZZSpacePart.java +298077bc0edf3d058748407c5d24661e ./Java/ZZTextView.java +89ca6a42d087bc28c27b81c9ced7779c ./Java/ZZTraverseCB.java +37b6366ee65d85d9540347e09ff11c5e ./Java/ZZUpdateManager.java +afdaf3509d26f0f06a8c0104bba63ffa ./Java/ZZUtil.java +38791925547399c362d052e8ee7dda24 ./Java/ZZViewComponent.java +8bdf80dd0a062d399c269f140b89d055 ./Java/ZZView.java +b518f1cc09de4da58cc203f0842fd574 ./Java/ZZWindows.java +6e29c688d912da12b66b73e32b03d812 ./LICENSE.lgpl +bb4bb554d0818bcbf54275d78c70cfae ./LICENSE.xpl +9a693c8ce0e2afc4c1b99c1c80f5946f ./makedist.param +8dcbbd155ce2854e8c0371d13e1337ac ./makedist.sh +6decdb20247d44deed82eecbfbc99b62 ./Makefile +265f410d6d78f4c565f2325f760fe9f1 Manifest +3f45193ab931aaf4910d399b8ce7a1a3 ./manifest-filter.lst +a79bfc4c2d3a4adc0cee5273b85046f4 ./manifest-filter.pl +925a6fd17158ccbf3ef6d75bfb79ae76 ./Modules/applet/example1.html +a1c76ce46af6a642dcd433260b02b368 ./Modules/applet/ZZApplet.java +7914102ab0af3c1e61dd56b8d37a4732 ./Modules/awtool/AwtCursor.java +81e211e55b5ab1fc18f1e02dc80d9935 ./Modules/awtool/AwtLink.java +18808224277fbc4664cffea2aa054dab ./Modules/awtool/AwtLink.zob +c28881dd64182b6899ae648f5c07407d ./Modules/awtool/AwtMetricsFC.java +cfa506eaff1db1ee91386d634d38d4e5 ./Modules/awtool/AwtMetricsFC2.java +f31c60623b10cfc9af3313506b5fa467 ./Modules/awtool/AwtMetrics.java +881358e7558e77fb450c1377a770b680 ./Modules/awtool/AwtMetricsNormal.java +7ea0a19501d9f9e75ee6baf4770a81e0 ./Modules/awtool/AwtMetrics.zob +90b1092e03be1e58b4426d6695602f2a ./Modules/awtool/AwtNileView.java +889be573d84a07b4aec97509f481ca60 ./Modules/awtool/AwtNote.java +f23bbd93b7c59cf5e292eb24ee7985eb ./Modules/awtool/AwtNote.zob +49e875a34ed9750e38e278841fc4d0a2 ./Modules/awtool/Awtool.java +cef39b65785a3d71db870df7de2fa257 ./Modules/awtool/Awtool.zob +55a79e0625571c254e2523b9239afa20 ./Modules/awtool/AwtUtil.java +0c9126c0cda42f44e6b0284c42a5ff2e ./Modules/awtool/AwtView1.java +e7ae0effd0e83a15ace6c09ecf072893 ./Modules/awtool/BooleanMesh.java +9c45120d5ec02b5116164ccda4cc9f29 ./Modules/awtool/README +df257f3b54e2796b57fd703b7c78c4b9 ./Modules/awtool/TODO +42bb6f87a096a94cbcd6df72e63b3cd4 ./Modules/awtool/ZObCellRepr.java +f4a7f9e53dbf85b71ac8b03020aa6162 ./Modules/benchmark/GraphBench.java +1cbe9556eb901da9d34cc511d85eadca ./Modules/benchmark/java2d/Java2DBench.java +698ef080d04a7e3205c14f327e3fbbf7 ./Modules/benchmark/README +442405e5bd142d29ee43a4b2848b8deb ./Modules/benchmark/ZZBench.java +a6ea06432827282fb8eba069c7457280 ./Modules/database/createscript.pl +c148624b523de50a7d740653421c6099 ./Modules/database/DB0.java +dd0f9e5d1ca7b455744883bc39f48182 ./Modules/database/zz.queries +fca6ec8dd5439eb8a9856330110b25ed ./Modules/database/zz.sql +c36795bc13e8f3e78acdda3220224c2d ./Modules/daytimedemo/Calendar2.zob +04dc4a14979ee2bbc0e196b47b6302f4 ./Modules/daytimedemo/ClockCellView.zob +b555e3bc30ed4be43c44de307fbe3e75 ./Modules/daytimedemo/DayTimeDemo.zob +d2ebeeb0ec57e273fd71690baab006cb ./Modules/extern/Extern.java +5a44ab88eb59011a452cf2ca68e403c1 ./Modules/hypergenealogy/HyperGenealogy.zob +e96d0641ec7001cdb3b2eb1350f3c93b ./Modules/iter/DimRecursor.java +87d3e70eeeca75b8e3ee710118d13769 ./Modules/iter/EnumVanishingView.zob +decd686d5e608e7fc02a1c6498315401 ./Modules/iter/Iter.java +441ffce54e957236ae894bb1172111ba ./Modules/iter/README +3e7f6dfab7ee63f04454951153d8534c ./Modules/joystick/LinuxJoystick.java +9bf4a1da80cd0c597838d74488dd35e8 ./Modules/mbox/SingleMail.zob +81bc7ecda0110c3ebef5c65381ebf375 ./Modules/mbox/ZZDateParser.java +28076d564164fc206e343bcccfe69f12 ./Modules/mbox/ZZMbox.java +b4b114d7c0986c88ce84fd19be00f7f8 ./Modules/mind/Mind.java +384325f9f6b863df4981a8e0f1237a17 ./Modules/mind/MindSundew.java +f021d23b01666e7edb8fd2af0062ac26 ./Modules/mind/MindSun.java +9dddf98d36021a0d0c574ca7009a7d62 ./Modules/multimedia/adjust.java +305674937b6d6d2508b12363be9db0da ./Modules/multimedia/crop.java +8d61ba772bca95443172c8796b244e51 ./Modules/multimedia/Default.java +9d6fc29d77e3ca903af1b33b93a633d2 ./Modules/multimedia/dots.java +bf58b8c5818f5bee16d76821b2b7e440 ./Modules/multimedia/image.java +5a2c682f2c634c74056d0fccae6412c4 ./Modules/multimedia/MediaFlobFactory.java +f533341e59d3539406471299cbcf853a ./Modules/multimedia/MediaFlobView.java +12424b3fff597bd6c634d6a47ca256fe ./Modules/multimedia/MediaMath.java +8e20f948baf967d3dd1e2ce5e872b4e7 ./Modules/multimedia/MediaZOb.java +e2a70dd0c140626e8f525df72f176d3e ./Modules/multimedia/mm.java +5cd0a9745ec7f52bbb86cefc6d23094d ./Modules/multimedia/move.java +a169b3a6a554575ed74171dc3d494715 ./Modules/multimedia/Pixels.java +c7c02a0ade7c29e8a9effb00b3389684 ./Modules/multimedia/PolygonRenderer.java +e12886d243c539d79b68ccb9d7609d31 ./Modules/multimedia/Polygons.java +9db8ec02f44a73346f1e00f1fcaf0c67 ./Modules/multimedia/readme.html +6fe23b7c55f8293450a1391ecba4008f ./Modules/multimedia/rect.java +9c13144d01a5c7ec95b50121643f88e5 ./Modules/multimedia/sin.java +cca8c0aa10bf519dafef2ea786352c61 ./Modules/nile/draft/Nile3Ops.java +97f8d9290fd19954205e8f461b721ec2 ./Modules/nile/draft/Nile3Part.java +e35c48b29e0f3ded057487715e35e1ca ./Modules/nile/draft/Nile3Pos.java +8f290f6cf73fecaff68e3a4f64ddc7d8 ./Modules/nile/draft/Nile3Unit.java +65ab721b13b54b57d24b8f1486d753c9 ./Modules/nile/NileApplet.java +2fdf3909c59af46363af5f70d2dc459c ./Modules/nile/NileDemo.java +8f037e44ee9f5bf79541adf1338adfa0 ./Modules/nile/Nile1Div.java +dc1a90edfd00fa9b3f9cf2db7fa6657d ./Modules/nile/Nile1GenTreeModel.java +801ea73772a6f6e91cbc825c05f930c6 ./Modules/nile/Nile1.java +edb2acc377ed1716f588a047dbd041db ./Modules/nile/Nile1Ops.java +11eab265c949ad2d8895263596f7da4e ./Modules/nile/Nile1Text.java +0cb9ec21d960fecfa8506e21af8a831e ./Modules/nile/Nile1View.zob +b6d533a7380625a0a802ae2155c15c1c ./Modules/nile/Nile2Iter.java +52a9ef49ce3dccb1b72073ff15b5de2d ./Modules/nile/Nile2Ops.java +96e34331465935136e81a015459ceed1 ./Modules/nile/Nile2Test.java +97ece27591313342b802534e883e7cad ./Modules/nile/Nile2Unit.java +1d741db89036b2aefa009238bd84a6c2 ./Modules/nile/README +644c964d0c8f6beb1af74ddb4b5734e6 ./Modules/nile/SplitNileDemo.java +5fd2907b150c1bfbfc77d7c6bb9e2e90 ./Modules/nile/SplitNileView.zob +d9a63d5cfd0926c89b75308b211eaa17 ./Modules/notemap/Notemap.zob +6e6b4dc23ad964beed3335a3ea88035a ./Modules/openGL/fi_iki_lukka_ZZOpenGLGraphics.h +8ed706298c05f9293ad481460a8e2a1f ./Modules/openGL/Makefile +b72792999c769a5a4668acb981da4b3f ./Modules/openGL/OpenGLCloud.java +68f822570b0fd62c48e80b2f8f949c1c ./Modules/openGL/ZZOpenGLGraphics.cc +c9ff5358229253e54d4fd9fe5c1121e7 ./Modules/openGL/ZZOpenGLGraphics.java +b9352a005581d78ad641aabd7f1738c1 ./Modules/panes/PaneView.zob +109b8aae81253d4acb26cfb7207c3f7a ./Modules/prez/Prez.java +85b728d7e4f141fb13e12c96ea9a1c39 ./Modules/prez/PrezRaster.zob +7b1376e584c6e586d26f2e613a7d497e ./Modules/README +40473ff9b47c2a7330d421731b73cc64 ./Modules/servlet/startjetty +efa3493aad01d13ad2f9f210c5e4ca0f ./Modules/servlet/VCServlet.java +2dc1e5f825c2ab8e0d46f507b404eb54 ./Modules/servlet/ZZServlet.java +b6b5f4994fdf46ec70adb4642b99bb2a ./Modules/servlet/zzserv.prp +4dad7b0e145abf8c2ac648abfe5d8033 ./Modules/servlet/zzserv2.prp +e339836283cdfa36e93b7e5afd03a17f ./Modules/sound/gsm_def.h +0e428af0a5e2ccb12fb3b76f4e84d5c8 ./Modules/sound/gsm_player.c +da859ad6c6224eafe57ef07ac0f8b3ad ./Modules/sound/gsm_recorder.c +03c79cf40080ec4ac2a58a0b1c817a7f ./Modules/sound/org_gzigzag_module_SimplePlayer.h +8491ce664ebe723a9f22f0a2cdf5aa7f ./Modules/sound/org_gzigzag_module_SimpleRecorder.h +0caad9d88177f6991ca39fd3679b166c ./Modules/sound/Player.java +c71d6c6056c9555d3a1de830888d7423 ./Modules/sound/Recorder.java +e86bae8148f7e5bd877284f12c50c099 ./Modules/sound/SimplePlayer.java +e29193f3dc59ad4fc74771a1581ce5ec ./Modules/sound/SimpleRecorder.java +f884549c0590a3ea5651d04de97285c0 ./Modules/sound/Sound.java +8fe08f3f70828049a7276669c3235072 ./Modules/test/README +5e2f8711d48a02d3b3b45e4311bf8224 ./Modules/test/TestClang1.java +67a1c141d8b7f4654c6c7a028145b628 ./Modules/test/TestHuge.java +a0f11cc84c5e66d1bf49f6c3d5514ced ./Modules/test/TestUndo.java +03094b5a42d3e32d8df43fc471f309f8 ./Modules/textcloud/TextCloud.zob +a34096038d953cd2cae93d51981c588c ./Modules/virtualcommunity/MessageFlobFactory.zob +0f6b87054720c74b728f26dcf84013c7 ./Modules/virtualcommunity/VCView1.java +6d48cd9983d11b562721b76a43f45bcf ./Modules/virtualcommunity/VCView2.java +b421b182b49668d5b7d9ccb3af9a2834 ./Modules/virtualcommunity/VCView3.java +b115cbae69e00e607a73d7ab54d27bc5 ./Modules/virtualcommunity/VCView4.java +e86b2443ae40d64a8d1bfd1eb8f5b99d ./Modules/virtualcommunity/VirtualCommunity.zob +fd3ad984d56a3d542290b3d8e59e431c ./Modules/vob/Connection.java +a5cf512f53454333ec7f763cb7b6658d ./Modules/vob/View.java +9513ba48c2b3a8a47e2f5f5b56f574a8 ./Modules/vob/Vob.java +01ed0350f167ed4454822c61c7379b5b ./Modules/vob/VobSet.java +b43e23e0cc03638782677d161e252b19 ./Modules/vob/VobStore.java +18da034b97bdb8ff5a8ce588a244d564 ./Modules/wordnet/conv.pl +def2c8a136ffe14b63ca7d1213187e9f ./Modules/xml/old2xml.pl +dc730e0e76b43a6433e391844e72abb2 ./Modules/xml/XML.java +94ddfe1cfcc45793b316f452024539ef ./Modules/zaubertrank/old/Actions.java +8ce6fd998eb35420d87626c1193d96b6 ./Modules/zaubertrank/old/Evaluator.java +039a8f25f90237e964d00775cdc8af58 ./Modules/zaubertrank/old/ParsedView.zob +68730b83954f598ebdebb333ac01a80b ./Modules/zaubertrank/old/Parser.java +6462d2438a93ffcbd4925972c4faf6e0 ./Modules/zaubertrank/old/Primitive.java +bc016fdfcc7069ddb17c9ea124dab505 ./Modules/zaubertrank/old/PrimitiveSet.java +3b07c9957a9d5a935b7cbc1412cf552c ./Modules/zaubertrank/old/SimpleView.zob +b92b437eb5fdee5189275ec755578265 ./Modules/zaubertrank/old/TokenFlob.java +38251a8ee6e30f4f55ac6ef2d1fe8d82 ./Modules/zaubertrank/old/TokenGrouper.java +d95d253353c6eb6c8274894cdb7b55a0 ./Modules/zaubertrank/old/Zaubertrank.java +c7990c975905c7ab892e8db298573ebb ./Modules/zaubertrank/old/ZaubertrankPart.java +448ab34951f8b280a6a2b15e5b1e4d04 ./Modules/zaubertrank/README.html +4b9d931e54c8a797b70be0c2c370a4ca ./Modules/zaubertrank/TokenTextCellView.java +7db224e3dbcbb542a175a1d60c86420a ./Modules/zaubertrank/ZaubertrankCellView.java +21d6102d124c44cb0beae241f33d2477 ./Modules/ztp/client/Action.java +de3230501ca36d4f1c26d5838b27ec45 ./Modules/ztp/client/Get.java +561c2a7d399ce6b9ba246eb9860e1416 ./Modules/ztp/client/Put.java +f9731410bbe95f52c662a3f356a45928 ./Modules/ztp/client/RemotePieceData.zob +6f30aadbc2073a58e438a766df09c9f9 ./Modules/ztp/client/Response.java +9f4f56ecad69f12874408a7543b5af14 ./Modules/ztp/client/Session.java +e4e245e2e119413373846528a1cf79e4 ./Modules/ztp/client/Subspace.java +f5a9fb3187f1ab9733fb2c57f4b28eb4 ./Modules/ztp/common/LineBufferedIO.java +0eed92e105cd4d42ec6c0e3574414df4 ./Modules/ztp/common/SubspaceDump.java +8286072ad1a37d6920aa84df6e0429dd ./Modules/ztp/server/GetMessage.java +a9150d5a7d4dec47a28563c84b9c5ff0 ./Modules/ztp/server/Listener.java +dc9c6045954c19bfbbafab16ff2af332 ./Modules/ztp/server/PutMessage.java +36fe65bee1db36c2ee506b9c5cfbffe6 ./Modules/ztp/server/Session.java +ad0198d0b647b9617e5fc37738bde56d ./Modules/ztp/server/UserManager.java +2096f7fd82609c8d98c40049e9ab6ea3 ./Modules/ztp/server/UserRecord.zob +08df1a8d7c09cd19233f3780bd9c8725 ./Modules/ztp/ZTPclient.java +bbd341b64c77696ba00a03140b7843b5 ./Modules/ztp/ZTPserver.java +c95342b5e64993c1aa4028c86d76c560 ./NEWS +717dda13238b80ff4e29e9f43293df41 ./Perl/cperl.pl +7cbc4f0e01357d4fdb273036b1232b05 ./Perl/PerlServImpl.pm +173087e5db7ad8338c6a9bb679938d14 ./Perl/README +2e2d54b8968a60f83b12c23ca7f425ca ./Perl/sperl.pl +b98bb2587720d03b603b8a3ae5249864 ./Perl/ZZPerlDBServ.pm +d751f660be9ed043a72aa6a1732b70ed ./Perl/ZZPerlServ.pm +09cec273af30bd97132982a4ae71109d ./Perl/ZZPerlSimpleClient.pm +86508b9a1c70efeb16630b47abe8071f ./README +523f7f8a2368d300345949dfb006cae4 ./VERSION