Browse Source

Added new C++ web application for TreeFrog Framework.

AOYAMA Kazuharu 12 years ago
parent
commit
c455de0eff
47 changed files with 1706 additions and 0 deletions
  1. 0 0
      treefrog/__init__.py
  2. 16 0
      treefrog/appbase.pri
  3. 13 0
      treefrog/benchmark_config
  4. 206 0
      treefrog/config/application.ini
  5. 44 0
      treefrog/config/database.ini
  6. 29 0
      treefrog/config/development.ini
  7. 51 0
      treefrog/config/initializers/internet_media_types.ini
  8. 38 0
      treefrog/config/logger.ini
  9. 27 0
      treefrog/config/mongodb.ini
  10. 10 0
      treefrog/config/routes.cfg
  11. 63 0
      treefrog/config/validation.ini
  12. 47 0
      treefrog/controllers/applicationcontroller.cpp
  13. 29 0
      treefrog/controllers/applicationcontroller.h
  14. 21 0
      treefrog/controllers/controllers.pro
  15. 110 0
      treefrog/controllers/fortunecontroller.cpp
  16. 30 0
      treefrog/controllers/fortunecontroller.h
  17. 22 0
      treefrog/controllers/jsoncontroller.cpp
  18. 23 0
      treefrog/controllers/jsoncontroller.h
  19. 131 0
      treefrog/controllers/worldcontroller.cpp
  20. 34 0
      treefrog/controllers/worldcontroller.h
  21. 1 0
      treefrog/helpers/applicationhelper.cpp
  22. 11 0
      treefrog/helpers/applicationhelper.h
  23. 13 0
      treefrog/helpers/helpers.pro
  24. 83 0
      treefrog/models/fortune.cpp
  25. 43 0
      treefrog/models/fortune.h
  26. 19 0
      treefrog/models/models.pro
  27. 31 0
      treefrog/models/sqlobjects/fortuneobject.h
  28. 31 0
      treefrog/models/sqlobjects/worldobject.h
  29. 85 0
      treefrog/models/world.cpp
  30. 43 0
      treefrog/models/world.h
  31. 28 0
      treefrog/public/403.html
  32. 28 0
      treefrog/public/404.html
  33. 28 0
      treefrog/public/413.html
  34. 29 0
      treefrog/public/500.html
  35. 36 0
      treefrog/setup.py
  36. 2 0
      treefrog/treefrog.pro
  37. 22 0
      treefrog/views/_src/_src.pro
  38. 30 0
      treefrog/views/fortune/edit.erb
  39. 27 0
      treefrog/views/fortune/entry.erb
  40. 35 0
      treefrog/views/fortune/index.erb
  41. 21 0
      treefrog/views/fortune/show.erb
  42. 1 0
      treefrog/views/mailer/.trim_mode
  43. 2 0
      treefrog/views/views.pro
  44. 30 0
      treefrog/views/world/edit.erb
  45. 27 0
      treefrog/views/world/entry.erb
  46. 35 0
      treefrog/views/world/index.erb
  47. 21 0
      treefrog/views/world/show.erb

+ 0 - 0
treefrog/__init__.py


+ 16 - 0
treefrog/appbase.pri

@@ -0,0 +1,16 @@
+win32 {
+  INCLUDEPATH += $$quote($$(TFDIR)\\include)
+  LIBS += -L$$quote($$(TFDIR)\\bin)
+  CONFIG(debug, debug|release) {
+    LIBS += -ltreefrogd1
+  } else {
+    LIBS += -ltreefrog1
+  }
+} else {
+  macx {
+    LIBS += -framework treefrog
+  } else {
+    LIBS += -ltreefrog
+  }
+  unix:INCLUDEPATH += /usr/include/treefrog
+}

+ 13 - 0
treefrog/benchmark_config

@@ -0,0 +1,13 @@
+{
+  "framework": "treefrog",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json/json",
+      "db_url": "/world/random",
+      "query_url": "/world/queries/",
+      "port": 8800,
+      "sort": 117
+    }
+  }]
+}

+ 206 - 0
treefrog/config/application.ini

@@ -0,0 +1,206 @@
+##
+## Application settings file
+##
+[General]
+
+# Listens on the specified port.
+ListenPort=8800
+
+# Sets the codec used by 'QObject::tr()' and 'toLocal8Bit()' to the
+# QTextCodec for the specified encoding. See QTextCodec class reference.
+InternalEncoding=UTF-8
+
+# Sets the codec for http output stream to the QTextCodec for the
+# specified encoding. See QTextCodec class reference.
+HttpOutputEncoding=UTF-8
+
+# Sets the charset parameter of 'text/html' in the HTTP Content-Type
+# header to the specified string.
+HtmlContentCharset=UTF-8
+
+# Sets a language/country pair, such as en_US, ja_JP, etc.
+# If this value is empty, the system's locale is used.
+Locale=
+
+# Specify the multiprocessing module, such as 'thread' or 'prefork'
+MultiProcessingModule=thread
+
+# Specify the absolute or relative path of the temporary directory
+# for HTTP uploaded files. Uses system default if not specified.
+UploadTemporaryDirectory=tmp
+
+# Specify setting files for SQL databases.
+SqlDatabaseSettingsFiles=database.ini
+
+# Specify the setting file for MongoDB.
+MongoDbSettingsFile=
+
+# Specify the directory path to store SQL query files
+SqlQueriesStoredDirectory=sql/
+
+# Determines whether it renders views without controllers directly
+# like PHP or not, which views are stored in the directory of
+# app/views/direct. By default, this parameter is false.
+DirectViewRenderMode=false
+
+# Specify a file path for system log.
+SystemLogFile=log/treefrog.log
+
+# Specify a file path for SQL query log.
+# If it's empty or the line is commented out, output to SQL query log
+# is disabled.
+SqlQueryLogFile=log/query.log
+
+# Determines whether the application aborts (to create a core dump
+# on Unix systems) or not when it output a fatal message by tFatal()
+# method.
+ApplicationAbortOnFatal=false
+
+# This directive specifies the number of bytes from 0 (meaning
+# unlimited) to 2147483647 (2GB) that are allowed in a request body.
+LimitRequestBody=0
+
+# If false is specified, the protective function against cross-site request
+# forgery never work; otherwise it's enabled.
+EnableCsrfProtectionModule=false
+
+##
+## Session section
+##
+Session.Name=TFSESSION
+
+# Specify the session store type, such as 'sqlobject', 'file', 'cookie'
+# or plugin module name.
+Session.StoreType=cookie
+
+# Replaces the session ID with a new one each time one connects, and
+# keeps the current session information.
+Session.AutoIdRegeneration=false
+
+# Specifies the lifetime of the session in seconds. The value 0 means
+# "until the browser is closed." Defaults to 0.
+Session.LifeTime=0
+
+# Specifies path to set in the session cookie. Defaults to /.
+Session.CookiePath=/
+
+# Probability that the garbage collection starts.
+# If 100 specified, the GC of sessions starts at the rate of once per 100
+# accesses. If 0 specified, the GC never starts.
+Session.GcProbability=100
+
+# Specifies the number of seconds after which session data will be seen as
+# 'garbage' and potentially cleaned up.
+Session.GcMaxLifeTime=1800
+
+# Secret key for verifying cookie session data integrity.
+# Enter at least 30 characters and all random.
+Session.Secret=0I3EINu8nxl1hMu0dVDdDpIvbT2zKs
+
+# Specify CSRF protection key.
+# Uses it in case of cookie session.
+Session.CsrfProtectionKey=_csrfId
+
+##
+## MPM Thread section
+##
+
+# Maximum number of server threads allowed to start
+MPM.thread.MaxServers=512
+
+##
+## MPM Prefork section
+##
+
+# Maximum number of server processes allowed to start
+MPM.prefork.MaxServers=20
+
+# Minimum number of server processes allowed to start
+MPM.prefork.MinServers=5
+
+# Number of server processes which are kept spare
+MPM.prefork.SpareServers=5
+
+##
+## SystemLog settings
+##
+
+# Specify the system log file name.
+SystemLog.FilePath=log/treefrog.log
+
+# Specify the layout of the system log
+#  %d : Date-time
+#  %p : Priority (lowercase)
+#  %P : Priority (uppercase)
+#  %t : Thread ID (dec)
+#  %T : Thread ID (hex)
+#  %i : PID (dec)
+#  %I : PID (hex)
+#  %m : Log message
+#  %n : Newline code
+SystemLog.Layout="%d %5P [%t] %m%n"
+
+# Specify the date-time format of the system log
+SystemLog.DateTimeFormat="yyyy-MM-dd hh:mm:ss"
+
+##
+## AccessLog settings
+##
+
+# Specify the access log file name.
+AccessLog.FilePath=log/access.log
+
+# Specify the layout of the access log.
+#  %h : Remote host
+#  %d : Date-time the request was received
+#  %r : First line of request
+#  %s : Status code
+#  %O : Bytes sent, including headers, cannot be zero
+#  %n : Newline code
+AccessLog.Layout="%h %d \"%r\" %s %O%n"
+
+# Specify the date-time format of the access log
+AccessLog.DateTimeFormat="yyyy-MM-dd hh:mm:ss"
+
+##
+## ActionMailer section
+##
+
+# Specify the delivery method such as "smtp" or "sendmail".
+# If empty, the mail is not sent.
+ActionMailer.DeliveryMethod=smtp
+
+# Specify the character set of email. The system encodes with this codec,
+# and sends the encoded mail.
+ActionMailer.CharacterSet=UTF-8
+
+##
+## ActionMailer SMTP section
+##
+
+# Specify the connection's host name or IP address.
+ActionMailer.smtp.HostName=
+
+# Specify the connection's port number.
+ActionMailer.smtp.Port=
+
+# Enables SMTP authentication if true; disables SMTP
+# authentication if false.
+ActionMailer.smtp.Authentication=false
+
+# Specify the user name for SMTP authentication.
+ActionMailer.smtp.UserName=
+
+# Specify the password for SMTP authentication.
+ActionMailer.smtp.Password=
+
+# Enables the delayed delivery of email if true. If enabled, deliver() method
+# only adds the email to the queue and therefore the method doesn't block.
+ActionMailer.smtp.DelayedDelivery=false
+
+##
+## ActionMailer Sendmail section
+## 
+
+#ActionMailer.sendMail.CommandLocation=/usr/sbin/sendmail
+

+ 44 - 0
treefrog/config/database.ini

@@ -0,0 +1,44 @@
+#
+# Database settings file
+#
+
+# The currently available driver types are:  
+#  [Driver Type] [Description]
+#   QDB2          IBM DB2
+#   QIBASE        Borland InterBase Driver
+#   QMYSQL        MySQL Driver
+#   QOCI          Oracle Call Interface Driver
+#   QODBC         ODBC Driver (includes Microsoft SQL Server)
+#   QPSQL         PostgreSQL Driver
+#   QSQLITE       SQLite version 3 or above
+#   QSQLITE2      SQLite version 2
+#
+# In case of SQLite, specify the DB file path to DatabaseName as follows;
+# DatabaseName=db/dbfile
+
+[dev]
+DriverType=QMYSQL
+DatabaseName=hello_world
+HostName=localhost
+Port=
+UserName=root
+Password=secret
+ConnectOptions=
+
+[test]
+DriverType=QMYSQL
+DatabaseName=
+HostName=localhost
+Port=
+UserName=
+Password=
+ConnectOptions=
+
+[product]
+DriverType=QMYSQL
+DatabaseName=hello_world
+HostName=localhost
+Port=
+UserName=root
+Password=secret
+ConnectOptions=

+ 29 - 0
treefrog/config/development.ini

@@ -0,0 +1,29 @@
+##
+## Development settings file
+##
+[General]
+
+##
+## Template system section
+##
+
+# Specify the template system of view, ERB or Otama.
+TemplateSystem=ERB
+
+
+##
+## ERB section
+## 
+
+# Specify the trim mode of ERB.
+#  0 : off
+#  1 : normal trim mode
+#  2 : strong trim mode
+Erb.DefaultTrimMode=1
+
+
+##
+## Otama section
+##
+Otama.ReplaceMarker=%%
+

+ 51 - 0
treefrog/config/initializers/internet_media_types.ini

@@ -0,0 +1,51 @@
+# 
+# Internet media type settings file
+#
+# (extension)=(internet media type)
+
+[General]
+# application
+pdf=application/pdf
+js=application/javascript
+zip=application/zip
+ogg=application/ogg
+ogx=application/ogg
+doc=application/msword
+xls=application/vnd.ms-excel
+ppt=application/vnd.ms-powerpoint
+
+# audio
+oga=audio/ogg
+mp3=audio/mpeg
+m4a=audio/mp4
+
+# image
+jpeg=image/jpeg
+jpg=image/jpeg
+gif=image/gif
+png=image/png
+tif=image/tiff
+tiff=image/tiff
+ico=image/vnd.microsoft.icon
+
+# text
+txt=text/plain
+html=text/html
+htm=text/html
+shtml=text/html
+xml=text/xml
+rss=text/xml
+rtf=text/rtf
+css=text/css
+csv=text/csv
+
+# video
+ogv=video/ogg
+3gp=video/3gpp
+3gpp=video/3gpp
+mp4=video/mp4
+mov=video/quicktime
+webm=video/webm
+flv=video/x-flv
+wmv=video/x-ms-wmv
+avi=video/x-msvideo

+ 38 - 0
treefrog/config/logger.ini

@@ -0,0 +1,38 @@
+##
+## Logger settings file
+##
+[General]
+
+# Specify loggers
+Loggers=FileLogger
+
+# Specify the default log text encoding. If not specified,
+# the codec will be based on a system locale.
+DefaultTextEncoding=
+
+##
+## FileLogger section
+##
+
+# Specify the application log file name.
+FileLogger.Target=log/app.log
+
+# Specify the layout of FileLogger.
+#  %d : date-time
+#  %p : priority (lowercase)
+#  %P : priority (uppercase)
+#  %t : thread ID (dec)
+#  %T : thread ID (hex)
+#  %i : PID (dec)
+#  %I : PID (hex)
+#  %m : log message
+#  %n : newline code
+FileLogger.Layout="%d %5P [%t] %m%n"
+
+# Specify the date-time format of FileLogger, see also QDateTime
+# class reference.
+FileLogger.DateTimeFormat="yyyy-MM-dd hh:mm:ss"
+
+# Outputs the logs of equal or higher priority than this.
+FileLogger.Threshold=debug
+

+ 27 - 0
treefrog/config/mongodb.ini

@@ -0,0 +1,27 @@
+#
+# MongoDB settings file
+#
+
+[dev]
+DatabaseName=mdb
+HostName=localhost
+Port=
+UserName=
+Password=
+ConnectOptions=
+
+[test]
+DatabaseName=
+HostName=
+Port=
+UserName=
+Password=
+ConnectOptions=
+
+[product]
+DatabaseName=
+HostName=
+Port=
+UserName=
+Password=
+ConnectOptions=

+ 10 - 0
treefrog/config/routes.cfg

@@ -0,0 +1,10 @@
+# routes.cfg
+
+# The priority is based upon order of creation:
+# first created -> highest priority.
+
+# Samples of regular routes:
+#   match  "/Book"  "Book#view"
+#   get    "/"  "Blog#index"
+#   post   "/New/:params"  "Account#entry"
+

+ 63 - 0
treefrog/config/validation.ini

@@ -0,0 +1,63 @@
+#
+# Validation settings file.
+#
+[General]
+
+# Sets the date format.
+# If you use the expression of short or long month name, note that the
+# application's locale settings. See QDate class reference.
+DateFormat="yyyy-MM-dd"
+
+# Sets the time format.
+# See QTime class reference.
+TimeFormat="hh:mm:ss"
+
+# Sets the date-time format.
+# If you use the expression of short or long month name, note that the
+# application's locale settings. See QDateTime class reference.
+DateTimeFormat="yyyy-MM-ddThh:mm:ss"
+
+#
+# Sets the default error messages below.
+#
+[ErrorMessage]
+
+# Required error
+0=This value is required.
+
+# MaxLength error
+1=This value is too long.
+
+# MinLength error
+2=This value is too short.
+
+# IntMax error
+3=This value is too big.
+
+# IntMin error
+4=This value is too small.
+
+# DoubleMax error
+5=This value is too big.
+
+# DoubleMin error
+6=This value is too small.
+
+# EMailAddress error
+7=This value is not email address.
+
+# Url error
+8=This value is invalid URL.
+
+# Date error
+9=This value is invalid date.
+
+# Time error
+10=This value is invalid time.
+
+# DateTime Error
+11=This value is invalid date or time.
+
+# UserDefined error
+12=This value is bad format.
+

+ 47 - 0
treefrog/controllers/applicationcontroller.cpp

@@ -0,0 +1,47 @@
+#include "applicationcontroller.h"
+
+
+ApplicationController::ApplicationController()
+    : TActionController()
+{ }
+
+ApplicationController::ApplicationController(const ApplicationController &)
+    : TActionController()
+{ }
+
+ApplicationController::~ApplicationController()
+{ }
+
+void ApplicationController::staticInitialize()
+{ }
+
+bool ApplicationController::preFilter()
+{
+    return true;
+}
+
+QString ApplicationController::jsonEncode(const QVariantMap &obj)
+{
+    QString ret("{");
+    for (QMap<QString, QVariant>::const_iterator i = obj.begin(); i != obj.end(); ++i) {
+        ret += QString("\"%1\": \"%2\", ").arg(i.key()).arg(i.value().toString());
+    }
+    ret.chop(2);
+    ret += QLatin1Char('}');
+    return ret;
+}
+
+QString ApplicationController::jsonEncode(const QList<QVariantMap> &lst)
+{
+    QString ret("[");
+    for (QListIterator<QVariantMap> it(lst); it.hasNext(); ) {
+      ret += jsonEncode(it.next());
+      ret += QLatin1String(", ");
+    }
+    ret.chop(2);
+    ret += QLatin1Char(']');
+    return ret;
+}
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(applicationcontroller)

+ 29 - 0
treefrog/controllers/applicationcontroller.h

@@ -0,0 +1,29 @@
+#ifndef APPLICATIONCONTROLLER_H
+#define APPLICATIONCONTROLLER_H
+
+#include <TActionController>
+#include <QVariantMap>
+#include <QList>
+#include "applicationhelper.h"
+
+
+class T_CONTROLLER_EXPORT ApplicationController : public TActionController
+{
+    Q_OBJECT
+public:
+    ApplicationController();
+    ApplicationController(const ApplicationController &other);
+    virtual ~ApplicationController();
+    static QString jsonEncode(const QVariantMap &obj);
+    static QString jsonEncode(const QList<QVariantMap> &list);
+
+public slots:
+    void staticInitialize();
+
+protected:
+    virtual bool preFilter();    
+};
+
+T_DECLARE_CONTROLLER(ApplicationController, applicationcontroller)
+
+#endif // APPLICATIONCONTROLLER_H

+ 21 - 0
treefrog/controllers/controllers.pro

@@ -0,0 +1,21 @@
+TARGET = controller
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT += network sql xml
+QT -= gui
+DEFINES += TF_DLL
+DESTDIR = ../lib
+INCLUDEPATH += ../helpers ../models
+DEPENDPATH  += ../helpers ../models
+LIBS += -L../lib -lhelper -lmodel
+
+include(../appbase.pri)
+
+HEADERS += applicationcontroller.h
+SOURCES += applicationcontroller.cpp
+HEADERS += fortunecontroller.h
+SOURCES += fortunecontroller.cpp
+HEADERS += worldcontroller.h
+SOURCES += worldcontroller.cpp
+HEADERS += jsoncontroller.h
+SOURCES += jsoncontroller.cpp

+ 110 - 0
treefrog/controllers/fortunecontroller.cpp

@@ -0,0 +1,110 @@
+#include "fortunecontroller.h"
+#include "fortune.h"
+
+
+FortuneController::FortuneController(const FortuneController &)
+    : ApplicationController()
+{ }
+
+void FortuneController::index()
+{
+    QList<Fortune> fortuneList = Fortune::getAll();
+    texport(fortuneList);
+    render();
+}
+
+void FortuneController::show(const QString &pk)
+{
+    Fortune fortune = Fortune::get(pk.toUInt());
+    texport(fortune);
+    render();
+}
+
+void FortuneController::entry()
+{
+    renderEntry();
+}
+
+void FortuneController::create()
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("fortune");
+    Fortune fortune = Fortune::create(form);
+    if (!fortune.isNull()) {
+        QString notice = "Created successfully.";
+        tflash(notice);
+        redirect(urla("show", fortune.id()));
+    } else {
+        QString error = "Failed to create.";
+        texport(error);
+        renderEntry(form);
+    }
+}
+
+void FortuneController::renderEntry(const QVariantMap &fortune)
+{
+    texport(fortune);
+    render("entry");
+}
+
+void FortuneController::edit(const QString &pk)
+{
+    Fortune fortune = Fortune::get(pk.toUInt());
+    if (!fortune.isNull()) {
+        renderEdit(fortune.toVariantMap());
+    } else {
+        redirect(urla("entry"));
+    }
+}
+
+void FortuneController::save(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QString error;
+    Fortune fortune = Fortune::get(pk.toUInt());
+    if (fortune.isNull()) {
+        error = "Original data not found. It may have been updated/removed by another transaction.";
+        tflash(error);
+        redirect(urla("edit", pk));
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("fortune");
+    fortune.setProperties(form);
+    if (fortune.save()) {
+        QString notice = "Updated successfully.";
+        tflash(notice);
+        redirect(urla("show", pk));
+    } else {
+        error = "Failed to update.";
+        texport(error);
+        renderEdit(form);
+    }
+}
+
+void FortuneController::renderEdit(const QVariantMap &fortune)
+{
+    texport(fortune);
+    render("edit");
+}
+
+void FortuneController::remove(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    Fortune fortune = Fortune::get(pk.toUInt());
+    fortune.remove();
+    redirect(urla("index"));
+}
+
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(fortunecontroller)

+ 30 - 0
treefrog/controllers/fortunecontroller.h

@@ -0,0 +1,30 @@
+#ifndef FORTUNECONTROLLER_H
+#define FORTUNECONTROLLER_H
+
+#include "applicationcontroller.h"
+
+
+class T_CONTROLLER_EXPORT FortuneController : public ApplicationController
+{
+    Q_OBJECT
+public:
+    FortuneController() { }
+    FortuneController(const FortuneController &other);
+
+public slots:
+    void index();
+    void show(const QString &pk);
+    void entry();
+    void create();
+    void edit(const QString &pk);
+    void save(const QString &pk);
+    void remove(const QString &pk);
+
+private:
+    void renderEntry(const QVariantMap &fortune = QVariantMap());
+    void renderEdit(const QVariantMap &fortune = QVariantMap());
+};
+
+T_DECLARE_CONTROLLER(FortuneController, fortunecontroller)
+
+#endif // FORTUNECONTROLLER_H

+ 22 - 0
treefrog/controllers/jsoncontroller.cpp

@@ -0,0 +1,22 @@
+#include "jsoncontroller.h"
+
+JsonController::JsonController(const JsonController &)
+    : ApplicationController()
+{ }
+
+void JsonController::index()
+{
+    // write codes
+}
+
+void JsonController::json()
+{
+    QVariantMap obj;
+    obj["message"] = "Hello, World!";
+
+    setContentType("application/json");
+    renderText(jsonEncode(obj), false);
+}
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(jsoncontroller)

+ 23 - 0
treefrog/controllers/jsoncontroller.h

@@ -0,0 +1,23 @@
+#ifndef JSONCONTROLLER_H
+#define JSONCONTROLLER_H
+
+#include "applicationcontroller.h"
+
+
+class T_CONTROLLER_EXPORT JsonController : public ApplicationController
+{
+    Q_OBJECT
+public:
+    JsonController() { }
+    JsonController(const JsonController &other);
+    bool sessionEnabled() const { return false; }
+    bool transactionEnabled() const { return false; }
+
+public slots:
+    void index();
+    void json();
+};
+
+T_DECLARE_CONTROLLER(JsonController, jsoncontroller)
+
+#endif // JSONCONTROLLER_H

+ 131 - 0
treefrog/controllers/worldcontroller.cpp

@@ -0,0 +1,131 @@
+#include "worldcontroller.h"
+#include "world.h"
+
+
+WorldController::WorldController(const WorldController &)
+    : ApplicationController()
+{ }
+
+void WorldController::index()
+{
+    QList<World> worldList = World::getAll();
+    texport(worldList);
+    render();
+}
+
+void WorldController::show(const QString &pk)
+{
+    World world = World::get(pk.toUInt());
+    texport(world);
+    render();
+}
+
+void WorldController::queries(const QString &num)
+{
+    QList<QVariantMap> worlds;
+    int d = num.toInt();
+    for (int i = 0; i < d; ++i) {
+        int id = Tf::random(9999) + 1;
+	World world = World::get(id);
+	worlds << world.toVariantMap();
+    }
+    setContentType("application/json");
+    renderText(jsonEncode(worlds), false);
+}
+
+void WorldController::random()
+{
+    int id = Tf::random(9999) + 1;
+    World world = World::get(id);
+    setContentType("application/json");
+    renderText(jsonEncode(world.toVariantMap()), false);
+}
+
+void WorldController::entry()
+{
+    renderEntry();
+}
+
+void WorldController::create()
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("world");
+    World world = World::create(form);
+    if (!world.isNull()) {
+        QString notice = "Created successfully.";
+        tflash(notice);
+        redirect(urla("show", world.id()));
+    } else {
+        QString error = "Failed to create.";
+        texport(error);
+        renderEntry(form);
+    }
+}
+
+void WorldController::renderEntry(const QVariantMap &world)
+{
+    texport(world);
+    render("entry");
+}
+
+void WorldController::edit(const QString &pk)
+{
+    World world = World::get(pk.toUInt());
+    if (!world.isNull()) {
+        renderEdit(world.toVariantMap());
+    } else {
+        redirect(urla("entry"));
+    }
+}
+
+void WorldController::save(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    QString error;
+    World world = World::get(pk.toUInt());
+    if (world.isNull()) {
+        error = "Original data not found. It may have been updated/removed by another transaction.";
+        tflash(error);
+        redirect(urla("edit", pk));
+        return;
+    }
+
+    QVariantMap form = httpRequest().formItems("world");
+    world.setProperties(form);
+    if (world.save()) {
+        QString notice = "Updated successfully.";
+        tflash(notice);
+        redirect(urla("show", pk));
+    } else {
+        error = "Failed to update.";
+        texport(error);
+        renderEdit(form);
+    }
+}
+
+void WorldController::renderEdit(const QVariantMap &world)
+{
+    texport(world);
+    render("edit");
+}
+
+void WorldController::remove(const QString &pk)
+{
+    if (httpRequest().method() != Tf::Post) {
+        return;
+    }
+
+    World world = World::get(pk.toUInt());
+    world.remove();
+    redirect(urla("index"));
+}
+
+
+// Don't remove below this line
+T_REGISTER_CONTROLLER(worldcontroller)

+ 34 - 0
treefrog/controllers/worldcontroller.h

@@ -0,0 +1,34 @@
+#ifndef WORLDCONTROLLER_H
+#define WORLDCONTROLLER_H
+
+#include "applicationcontroller.h"
+
+
+class T_CONTROLLER_EXPORT WorldController : public ApplicationController
+{
+    Q_OBJECT
+public:
+    WorldController() { }
+    WorldController(const WorldController &other);
+    bool sessionEnabled() const { return false; }
+    bool transactionEnabled() const { return false; }
+
+public slots:
+    void index();
+    void show(const QString &pk);
+    void queries(const QString &num);
+    void random();
+    void entry();
+    void create();
+    void edit(const QString &pk);
+    void save(const QString &pk);
+    void remove(const QString &pk);
+
+private:
+    void renderEntry(const QVariantMap &world = QVariantMap());
+    void renderEdit(const QVariantMap &world = QVariantMap());
+};
+
+T_DECLARE_CONTROLLER(WorldController, worldcontroller)
+
+#endif // WORLDCONTROLLER_H

+ 1 - 0
treefrog/helpers/applicationhelper.cpp

@@ -0,0 +1 @@
+#include "applicationhelper.h"

+ 11 - 0
treefrog/helpers/applicationhelper.h

@@ -0,0 +1,11 @@
+#ifndef APPLICATIONHELPER_H
+#define APPLICATIONHELPER_H
+
+#include <TGlobal>
+
+
+class T_HELPER_EXPORT ApplicationHelper
+{
+};
+
+#endif // APPLICATIONHELPER_H

+ 13 - 0
treefrog/helpers/helpers.pro

@@ -0,0 +1,13 @@
+TARGET = helper
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT  -= gui
+QT  += 
+DEFINES += TF_DLL
+DESTDIR = ../lib
+DEPENDPATH +=
+
+include(../appbase.pri)
+
+HEADERS += applicationhelper.h
+SOURCES += applicationhelper.cpp

+ 83 - 0
treefrog/models/fortune.cpp

@@ -0,0 +1,83 @@
+#include <TreeFrogModel>
+#include "fortune.h"
+#include "fortuneobject.h"
+
+Fortune::Fortune()
+    : TAbstractModel(), d(new FortuneObject)
+{ }
+
+Fortune::Fortune(const Fortune &other)
+    : TAbstractModel(), d(new FortuneObject(*other.d))
+{ }
+
+Fortune::Fortune(const FortuneObject &object)
+    : TAbstractModel(), d(new FortuneObject(object))
+{ }
+
+Fortune::~Fortune()
+{
+    // If the reference count becomes 0,
+    // the shared data object 'FortuneObject' is deleted.
+}
+
+uint Fortune::id() const
+{
+    return d->id;
+}
+
+QString Fortune::message() const
+{
+    return d->message;
+}
+
+void Fortune::setMessage(const QString &message)
+{
+    d->message = message;
+}
+
+Fortune &Fortune::operator=(const Fortune &other)
+{
+    d = other.d;  // increments the reference count of the data
+    return *this;
+}
+
+Fortune Fortune::create(const QString &message)
+{
+    FortuneObject obj;
+    obj.message = message;
+    if (!obj.create()) {
+        obj.clear();
+    }
+    return Fortune(obj);
+}
+
+Fortune Fortune::create(const QVariantMap &values)
+{
+    Fortune model;
+    model.setProperties(values);
+    if (!model.d->create()) {
+        model.d->clear();
+    }
+    return model;
+}
+
+Fortune Fortune::get(const uint &id)
+{
+    TSqlORMapper<FortuneObject> mapper;
+    return Fortune(mapper.findByPrimaryKey(id));
+}
+
+QList<Fortune> Fortune::getAll()
+{
+    return tfGetModelListByCriteria<Fortune, FortuneObject>(TCriteria());
+}
+
+TSqlObject *Fortune::data()
+{
+    return d.data();
+}
+
+const TSqlObject *Fortune::data() const
+{
+    return d.data();
+}

+ 43 - 0
treefrog/models/fortune.h

@@ -0,0 +1,43 @@
+#ifndef FORTUNE_H
+#define FORTUNE_H
+
+#include <QStringList>
+#include <QDateTime>
+#include <QVariant>
+#include <QSharedDataPointer>
+#include <TGlobal>
+#include <TAbstractModel>
+
+class TSqlObject;
+class FortuneObject;
+
+
+class T_MODEL_EXPORT Fortune : public TAbstractModel
+{
+public:
+    Fortune();
+    Fortune(const Fortune &other);
+    Fortune(const FortuneObject &object);
+    ~Fortune();
+
+    uint id() const;
+    QString message() const;
+    void setMessage(const QString &message);
+    Fortune &operator=(const Fortune &other);
+
+    static Fortune create(const QString &message);
+    static Fortune create(const QVariantMap &values);
+    static Fortune get(const uint &id);
+    static QList<Fortune> getAll();
+
+private:
+    QSharedDataPointer<FortuneObject> d;
+
+    TSqlObject *data();
+    const TSqlObject *data() const;
+};
+
+Q_DECLARE_METATYPE(Fortune)
+Q_DECLARE_METATYPE(QList<Fortune>)
+
+#endif // FORTUNE_H

+ 19 - 0
treefrog/models/models.pro

@@ -0,0 +1,19 @@
+TARGET = model
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT += sql
+QT -= gui
+DEFINES += TF_DLL
+DESTDIR = ../lib
+INCLUDEPATH += ../helpers sqlobjects
+DEPENDPATH  += ../helpers sqlobjects
+LIBS += -L../lib -lhelper
+
+include(../appbase.pri)
+
+HEADERS += sqlobjects/fortuneobject.h
+HEADERS += fortune.h
+SOURCES += fortune.cpp
+HEADERS += sqlobjects/worldobject.h
+HEADERS += world.h
+SOURCES += world.cpp

+ 31 - 0
treefrog/models/sqlobjects/fortuneobject.h

@@ -0,0 +1,31 @@
+#ifndef FORTUNEOBJECT_H
+#define FORTUNEOBJECT_H
+
+#include <TSqlObject>
+#include <QSharedData>
+
+
+class T_MODEL_EXPORT FortuneObject : public TSqlObject, public QSharedData
+{
+public:
+    uint id;
+    QString message;
+
+    enum PropertyIndex {
+        Id = 0,
+        Message,
+    };
+
+    QString tableName() const { return QLatin1String("Fortune"); }
+    int primaryKeyIndex() const { return Id; }
+    int autoValueIndex() const { return Id; }
+
+private:    /*** Don't modify below this line ***/
+    Q_OBJECT
+    Q_PROPERTY(uint id READ getid WRITE setid)
+    T_DEFINE_PROPERTY(uint, id)
+    Q_PROPERTY(QString message READ getmessage WRITE setmessage)
+    T_DEFINE_PROPERTY(QString, message)
+};
+
+#endif // FORTUNEOBJECT_H

+ 31 - 0
treefrog/models/sqlobjects/worldobject.h

@@ -0,0 +1,31 @@
+#ifndef WORLDOBJECT_H
+#define WORLDOBJECT_H
+
+#include <TSqlObject>
+#include <QSharedData>
+
+
+class T_MODEL_EXPORT WorldObject : public TSqlObject, public QSharedData
+{
+public:
+    uint id;
+    int randomnumber;
+
+    enum PropertyIndex {
+        Id = 0,
+        Randomnumber,
+    };
+
+    QString tableName() const { return QLatin1String("World"); }
+    int primaryKeyIndex() const { return Id; }
+    int autoValueIndex() const { return Id; }
+
+private:    /*** Don't modify below this line ***/
+    Q_OBJECT
+    Q_PROPERTY(uint id READ getid WRITE setid)
+    T_DEFINE_PROPERTY(uint, id)
+    Q_PROPERTY(int randomnumber READ getrandomnumber WRITE setrandomnumber)
+    T_DEFINE_PROPERTY(int, randomnumber)
+};
+
+#endif // WORLDOBJECT_H

+ 85 - 0
treefrog/models/world.cpp

@@ -0,0 +1,85 @@
+#include <TreeFrogModel>
+#include "world.h"
+#include "worldobject.h"
+
+World::World()
+    : TAbstractModel(), d(new WorldObject)
+{
+    d->randomnumber = 0;
+}
+
+World::World(const World &other)
+    : TAbstractModel(), d(new WorldObject(*other.d))
+{ }
+
+World::World(const WorldObject &object)
+    : TAbstractModel(), d(new WorldObject(object))
+{ }
+
+World::~World()
+{
+    // If the reference count becomes 0,
+    // the shared data object 'WorldObject' is deleted.
+}
+
+uint World::id() const
+{
+    return d->id;
+}
+
+int World::randomnumber() const
+{
+    return d->randomnumber;
+}
+
+void World::setRandomnumber(int randomnumber)
+{
+    d->randomnumber = randomnumber;
+}
+
+World &World::operator=(const World &other)
+{
+    d = other.d;  // increments the reference count of the data
+    return *this;
+}
+
+World World::create(int randomnumber)
+{
+    WorldObject obj;
+    obj.randomnumber = randomnumber;
+    if (!obj.create()) {
+        obj.clear();
+    }
+    return World(obj);
+}
+
+World World::create(const QVariantMap &values)
+{
+    World model;
+    model.setProperties(values);
+    if (!model.d->create()) {
+        model.d->clear();
+    }
+    return model;
+}
+
+World World::get(const uint &id)
+{
+    TSqlORMapper<WorldObject> mapper;
+    return World(mapper.findByPrimaryKey(id));
+}
+
+QList<World> World::getAll()
+{
+    return tfGetModelListByCriteria<World, WorldObject>(TCriteria());
+}
+
+TSqlObject *World::data()
+{
+    return d.data();
+}
+
+const TSqlObject *World::data() const
+{
+    return d.data();
+}

+ 43 - 0
treefrog/models/world.h

@@ -0,0 +1,43 @@
+#ifndef WORLD_H
+#define WORLD_H
+
+#include <QStringList>
+#include <QDateTime>
+#include <QVariant>
+#include <QSharedDataPointer>
+#include <TGlobal>
+#include <TAbstractModel>
+
+class TSqlObject;
+class WorldObject;
+
+
+class T_MODEL_EXPORT World : public TAbstractModel
+{
+public:
+    World();
+    World(const World &other);
+    World(const WorldObject &object);
+    ~World();
+
+    uint id() const;
+    int randomnumber() const;
+    void setRandomnumber(int randomnumber);
+    World &operator=(const World &other);
+
+    static World create(int randomnumber);
+    static World create(const QVariantMap &values);
+    static World get(const uint &id);
+    static QList<World> getAll();
+
+private:
+    QSharedDataPointer<WorldObject> d;
+
+    TSqlObject *data();
+    const TSqlObject *data() const;
+};
+
+Q_DECLARE_METATYPE(World)
+Q_DECLARE_METATYPE(QList<World>)
+
+#endif // WORLD_H

+ 28 - 0
treefrog/public/403.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html> 
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Forbidden</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Forbidden</h3>
+    <p>Accessing the page or resource you were trying to reach is absolutely forbidden.</p>
+  </div>
+</body>
+</html>

+ 28 - 0
treefrog/public/404.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html> 
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Page Not Found</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Page Not Found</h3>
+    <p>The server has not found anything matching the Request-URI.</p>
+  </div>
+</body>
+</html>

+ 28 - 0
treefrog/public/413.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Request Entity Too Large</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Request Entity Too Large</h3>
+    <p>The server is refusing to process a request because the request entity is larger than the server is willing or able to process.</p>
+  </div>
+</body>
+</html>

+ 29 - 0
treefrog/public/500.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+  <title>Internal Server Error</title>
+    <style type="text/css">
+	body { background-color: #fff; text-align: center; }
+	div.dialog {
+		width: 50%;
+		height: 150px;
+		padding: 0 4em;
+		margin: 4em auto 0 auto;
+		border: 1px solid #eee;
+		border-right-color: #444;
+		border-bottom-color: #444;
+		background-color: #eee;
+	}
+	h3 { color: #f00; line-height: 2em; }
+    </style>
+</head>
+
+<body>
+  <div class="dialog">
+    <h3>Internal Server Error</h3>
+    <p>The server encountered an unexpected condition which prevented it from fulfilling the request.
+</p>
+  </div>
+</body>
+</html>

+ 36 - 0
treefrog/setup.py

@@ -0,0 +1,36 @@
+
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+
+home = expanduser("~")
+
+##############
+# start(args)
+##############
+def start(args):
+  setup_util.replace_text("treefrog/config/database.ini", "HostName=.*", "HostName=" + args.database_host)
+
+  # 1. Generate Makefile
+  # 2. Compile applicaton
+  # 3. Clean log files
+  # 4. Start TreeFrog
+  try:
+    subprocess.check_call("qmake -r CONFIG+=release", shell=True, cwd="treefrog")
+    subprocess.check_call("make", shell=True, cwd="treefrog")
+    subprocess.check_call("rm -f ./*.log", shell=True, cwd="treefrog/log")
+    subprocess.check_call("treefrog -d " + home + "/FrameworkBenchmarks/treefrog", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+##############
+# stop()
+##############
+def stop():
+  try:
+    subprocess.call("treefrog -k abort " + home + "/FrameworkBenchmarks/treefrog", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 2 - 0
treefrog/treefrog.pro

@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = helpers models views controllers

+ 22 - 0
treefrog/views/_src/_src.pro

@@ -0,0 +1,22 @@
+TARGET = view
+TEMPLATE = lib
+CONFIG += shared x86_64
+QT += network xml
+QT -= gui
+DEFINES += TF_DLL
+INCLUDEPATH += ../../helpers ../../models
+DEPENDPATH  += ../../helpers ../../models
+DESTDIR = ../../lib
+LIBS += -L../../lib -lhelper -lmodel
+QMAKE_CLEAN = *.cpp source.list
+
+tmake.target = source.list
+tmake.commands = tmake -f ../../config/application.ini -v .. -d . -P
+tmake.depends = qmake
+QMAKE_EXTRA_TARGETS = tmake
+
+include(../../appbase.pri)
+!exists(source.list) {
+  system( $$tmake.commands )
+}
+include(source.list)

+ 30 - 0
treefrog/views/fortune/edit.erb

@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<% tfetch(QVariantMap, fortune); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Editing Fortune</h1>
+
+<%== formTag(urla("save", fortune["id"]), Tf::Post) %>
+  <p>
+    <label>ID<br /><input type="text" name="fortune[id]" value="<%= fortune["id"] %>" readonly="readonly" /></label>
+  </p>
+  <p>
+    <label>Message<br /><input type="text" name="fortune[message]" value="<%= fortune["message"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Update" />
+  </p>
+</form>
+
+<%== linkTo("Show", urla("show", fortune["id"])) %> |
+<%== linkTo("Back", urla("index")) %>
+</body>
+</html>

+ 27 - 0
treefrog/views/fortune/entry.erb

@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<% tfetch(QVariantMap, fortune); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>New Fortune</h1>
+
+<%== formTag(urla("create"), Tf::Post) %>
+  <p>
+    <label>Message<br /><input name="fortune[message]" value="<%= fortune["message"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Create" />
+  </p>
+</form>
+
+<%== linkTo("Back", urla("index")) %>
+
+</body>
+</html>

+ 35 - 0
treefrog/views/fortune/index.erb

@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+
+<h1>Listing Fortune</h1>
+
+<%== linkTo("New entry", urla("entry")) %><br />
+<br />
+<table border="1" cellpadding="5" style="border: 1px #d0d0d0 solid; border-collapse: collapse;">
+  <tr>
+    <th>ID</th>
+    <th>Message</th>
+  </tr>
+<% tfetch(QList<Fortune>, fortuneList); %>
+<% for (QListIterator<Fortune> it(fortuneList); it.hasNext(); ) {
+     const Fortune &i = it.next(); %>
+  <tr>
+    <td><%= i.id() %></td>
+    <td><%= i.message() %></td>
+    <td>
+      <%== linkTo("Show", urla("show", i.id())) %>
+      <%== linkTo("Edit", urla("edit", i.id())) %>
+      <%== linkTo("Remove", urla("remove", i.id()), Tf::Post, "confirm('Are you sure?')") %>
+    </td>
+  </tr>
+<% } %>
+</table>
+
+</body>
+</html>

+ 21 - 0
treefrog/views/fortune/show.erb

@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<%#include "fortune.h" %>
+<% tfetch(Fortune, fortune); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Showing Fortune</h1>
+<dt>ID</dt><dd><%= fortune.id() %></dd><br />
+<dt>Message</dt><dd><%= fortune.message() %></dd><br />
+
+<%== linkTo("Edit", urla("edit", fortune.id())) %> |
+<%== linkTo("Back", urla("index")) %>
+
+</body>
+</html>

+ 1 - 0
treefrog/views/mailer/.trim_mode

@@ -0,0 +1 @@
+0

+ 2 - 0
treefrog/views/views.pro

@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = _src

+ 30 - 0
treefrog/views/world/edit.erb

@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<%#include "world.h" %>
+<% tfetch(QVariantMap, world); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Editing World</h1>
+
+<%== formTag(urla("save", world["id"]), Tf::Post) %>
+  <p>
+    <label>ID<br /><input type="text" name="world[id]" value="<%= world["id"] %>" readonly="readonly" /></label>
+  </p>
+  <p>
+    <label>Randomnumber<br /><input type="text" name="world[randomnumber]" value="<%= world["randomnumber"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Update" />
+  </p>
+</form>
+
+<%== linkTo("Show", urla("show", world["id"])) %> |
+<%== linkTo("Back", urla("index")) %>
+</body>
+</html>

+ 27 - 0
treefrog/views/world/entry.erb

@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<%#include "world.h" %>
+<% tfetch(QVariantMap, world); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>New World</h1>
+
+<%== formTag(urla("create"), Tf::Post) %>
+  <p>
+    <label>Randomnumber<br /><input name="world[randomnumber]" value="<%= world["randomnumber"] %>" /></label>
+  </p>
+  <p>
+    <input type="submit" value="Create" />
+  </p>
+</form>
+
+<%== linkTo("Back", urla("index")) %>
+
+</body>
+</html>

+ 35 - 0
treefrog/views/world/index.erb

@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<%#include "world.h" %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+
+<h1>Listing World</h1>
+
+<%== linkTo("New entry", urla("entry")) %><br />
+<br />
+<table border="1" cellpadding="5" style="border: 1px #d0d0d0 solid; border-collapse: collapse;">
+  <tr>
+    <th>ID</th>
+    <th>Randomnumber</th>
+  </tr>
+<% tfetch(QList<World>, worldList); %>
+<% for (QListIterator<World> it(worldList); it.hasNext(); ) {
+     const World &i = it.next(); %>
+  <tr>
+    <td><%= i.id() %></td>
+    <td><%= i.randomnumber() %></td>
+    <td>
+      <%== linkTo("Show", urla("show", i.id())) %>
+      <%== linkTo("Edit", urla("edit", i.id())) %>
+      <%== linkTo("Remove", urla("remove", i.id()), Tf::Post, "confirm('Are you sure?')") %>
+    </td>
+  </tr>
+<% } %>
+</table>
+
+</body>
+</html>

+ 21 - 0
treefrog/views/world/show.erb

@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<%#include "world.h" %>
+<% tfetch(World, world); %>
+<html>
+<head>
+  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+  <title><%= controller()->name() + ": " + controller()->activeAction() %></title>
+</head>
+<body>
+<p style="color: red"><%=$ error %></p>
+<p style="color: green"><%=$ notice %></p>
+
+<h1>Showing World</h1>
+<dt>ID</dt><dd><%= world.id() %></dd><br />
+<dt>Randomnumber</dt><dd><%= world.randomnumber() %></dd><br />
+
+<%== linkTo("Edit", urla("edit", world.id())) %> |
+<%== linkTo("Back", urla("index")) %>
+
+</body>
+</html>