// This may look like C code, but it's really -*- C++ -*- /* * Copyright (C) 2008 Emweb bv, Herent, Belgium. * * See the LICENSE file for terms of use. */ #ifndef WAPPLICATION_ #define WAPPLICATION_ #include #include #include // even boost/poolfwd.hpp includes ... namespace boost { struct default_user_allocator_new_delete; template class pool; } #include #include #include #include #include #include #include #include #include namespace Wt { #ifndef WT_TARGET_JAVA /* * Symbols used to check that included version matches library version * against which you link. */ struct WtLibVersion { }; extern WT_API const WtLibVersion WT_INCLUDED_VERSION; #endif class WApplication; class WCombinedLocalizedStrings; class WContainerWidget; class WEnvironment; class WEvent; class WLoadingIndicator; class WLogEntry; class WResource; class WText; class WebSession; class RootContainer; class UpdateLockImpl; class SoundManager; /*! \brief Typedef for a function that creates WApplication objects. * * \sa WRun() * * \relates WApplication */ typedef std::function (const WEnvironment&)> ApplicationCreator; #ifdef WT_TARGET_JAVA /*! \brief An HTML Meta Header */ #endif // WT_TARGET_JAVA class MetaHeader { public: /*! \brief Constructor * * Creates a meta header. The lang and user agents are optional, and should * be an empty string if not used. */ MetaHeader(MetaHeaderType type, const std::string& name, const WString& content, const std::string& lang, const std::string& userAgent); MetaHeaderType type; std::string name, lang, userAgent; WString content; }; /*! \class WApplication Wt/WApplication.h Wt/WApplication.h * \brief Represents an application instance for a single session. * * \if cpp * * Each user session of your application has a corresponding * %WApplication instance. You need to create a new instance and return * it as the result of the callback function passed to WRun(). The * instance is the main entry point to session information, and holds * a reference to the root() of the widget tree. * * \elseif java * * Each user session of your application has a corresponding * %WApplication instance. You need to create a new instance and return * it as the result of {javadoclink WtServlet#createApplication(WEnvironment)}. * The instance is the main entry point to session information, * and holds a reference to the root() of the widget tree. * * \endif * * The recipe for a %Wt web application, which allocates new * WApplication instances for every user visiting the application is * thus: * * \if cpp * \code * std::unique_ptr createApplication(const WEnvironment& env) * { * // * // Optionally, check the environment and redirect to an error page. * // * bool valid = ...; * * std::unique_ptr app; * if (!valid) { * app = std::make_unique(env); * app->redirect("error.html"); * app->quit(); * } else { * // usually you will specialize your application class * app = std::make_unique(env); * * // * // Add widgets to app->root() and return the application object. * // * } * * return app; * } * \endcode * \elseif java * \code * public class HelloServlet extends WtServlet { * public HelloServlet() { * super(); * } * * public WApplication createApplication(WEnvironment env) { * // In practice, you will specialize WApplication and simply * // return a new instance. * WApplication app = new WApplication(env); * app.getRoot().addWidget(new WText("Hello world.")); * return app; * } * } * \endcode * \endif * * \if cpp * * Throughout the session, the instance is available through * WApplication::instance() (or through #wApp). The application may be * exited either using the method quit(), or because of a timeout * after the user has closed the window, but not because the user does * not interact: keep-alive messages in the background will keep the * session around as long as the user has the page opened. In either * case, the application object is deleted, allowing for cleanup of * the entire widget tree, and any other resources. * * \elseif java * * Throughout the session, the instance is available through the * static method WApplication::instance(), which uses thread-specific * storage to keep track of the current session. The application may * be exited either using the method quit(), or because of a timeout * after the user has closed the window, but not because the user does * not interact: keep-alive messages in the background will keep the * session around as long as the user has the page opened. * * \endif * * The %WApplication object provides access to session-wide settings, including: * * - circumstantial information through environment(), which gives * details about the user, start-up arguments, and user agent * capabilities. * - the application title with setTitle(). * - inline and external style sheets using styleSheet() and * useStyleSheet(). * - inline and external JavaScript using doJavaScript() and require(). * - the top-level widget in root(), representing the entire browser window, * or multiple top-level widgets using bindWidget() when deployed in * EntryPointType::WidgetSet mode to manage a number of widgets within a 3rd party page. * - definition of cookies using setCookie() to persist information across * sessions, which may be read using WEnvironment::getCookie() in a future * session. * - management of the internal path (that enables browser history and * bookmarks) using setInternalPath() and related methods. * - support for server-initiated updates with enableUpdates() * \if cpp * - localization information and message resources bundles using setLocale() * and messageResourceBundle(). * \elseif java * - localization information and message resources bundles, with * setLocale() and setLocalizedStrings() * \endif */ class WT_API WApplication : public WObject { public: /*! \brief Typedef for a function that creates WApplication objects. * * \sa WRun() */ typedef Wt::ApplicationCreator ApplicationCreator; /*! \brief Creates a new application instance. * * The \p environment provides information on the initial request, * user agent, and deployment-related information. */ #if defined(DOXYGEN_ONLY) || defined(WT_TARGET_JAVA) WApplication(const WEnvironment& environment); #else WApplication(const WEnvironment& environment, WtLibVersion version = WT_INCLUDED_VERSION); #endif #ifndef WT_TARGET_JAVA /*! \brief Destructor. * * The destructor deletes the root() container, and as a consequence * the entire widget tree. */ ~WApplication(); #endif // WT_TARGET_JAVA /*! \brief Returns the current application instance. * * \if cpp * This is the same as the global define #wApp. In a multi-threaded server, * this method uses thread-specific storage to fetch the current session. * \elseif java * This method uses thread-specific storage to fetch the current session. * \endif */ static WApplication *instance(); /*! \brief Returns the environment information. * * This method returns the environment object that was used when * constructing the application. The environment provides * information on the initial request, user agent, and * deployment-related information. * * \sa url(), sessionId() */ const WEnvironment& environment() const; /*! \brief Returns the root container. * * This is the top-level widget container of the application, and * corresponds to entire browser window. The user interface of your * application is represented by the content of this container. * * \if cpp * * The %root() widget is only defined when the application manages * the entire window. When deployed as a \link Wt::EntryPointType::WidgetSet * EntryPointType::WidgetSet\endlink application, there is no %root() container, and * \c 0 is returned. Instead, use bindWidget() to bind one or more * root widgets to existing HTML <div> (or other) elements on * the page. * * \elseif java * * The root() widget is only defined when the application manages * the entire window. When deployed as a \link Wt::EntryPointType::WidgetSet * EntryPointType::WidgetSet\endlink application, there is no %root() container, and * null is returned. Instead, use bindWidget() to bind * one or more root widgets to existing HTML <div> (or other) * elements on the page. * * \endif */ WContainerWidget *root() const { return widgetRoot_; } /*! \brief Finds a widget by name. * * This finds a widget in the application's widget hierarchy. It * does not only consider widgets in the root(), but also widgets * that are placed outside this root, such as in dialogs, or other * "roots" such as all the bound widgets in a widgetset application. * * \sa WWidget::setObjectName(), WWidget::find() */ WWidget *findWidget(const std::string& name); /** @name Style sheets and CSS */ //!@{ /*! \brief Returns a reference to the inline style sheet. * * Widgets may allow configuration of their look and feel through * style classes. These may be defined in this inline stylesheet, or * in external style sheets. * * It is usually preferable to use external stylesheets (and * consider more accessible). Still, the internal stylesheet has as * benefit that style rules may be dynamically updated, and it is * easier to manage logistically. * * \sa useStyleSheet() * \sa WWidget::setStyleClass() */ WCssStyleSheet& styleSheet() { return styleSheet_; } /*! \brief Adds an external style sheet. * * The \p link is a link to a stylesheet. * * The \p media indicates the CSS media to which this stylesheet * applies. This may be a comma separated list of media. The default * value is "all" indicating all media. * * This is an overloaded method for convenience, equivalent to: * \code * useStyleSheet(Wt::WCssStyleSheet(link, media)) * \endcode */ void useStyleSheet(const WLink& link, const std::string& media = "all"); /*! \brief Conditionally adds an external style sheet. * * This is an overloaded method for convenience, equivalent to: * \code * useStyleSheet(Wt::WLinkedCssStyleSheet(link, media), condition) * \endcode */ void useStyleSheet(const WLink& link, const std::string& condition, const std::string& media); /*! \brief Adds an external stylesheet. * * Widgets may allow configuration of their look and feel through * style classes. These may be defined in an inline stylesheet, * or in external style sheets. * * External stylesheets are inserted after the internal style sheet, * and can therefore override default styles set by widgets in the * internal style sheet. * External stylesheets must have valid link. * * If not empty, \p condition is a string that is used to apply the * stylesheet to specific versions of IE. Only a limited subset of * the IE conditional comments syntax is supported (since these are * in fact interpreted server-side instead of client-side). Examples * are: * * - "IE gte 6": only for IE version 6 or later. * - "!IE gte 6": only for IE versions prior to IE6. * - "IE lte 7": only for IE versions prior to IE7. * * \sa styleSheet(), useStyleSheet(const std::string&, const std::string&), * removeStyleSheet(const WLink& link) * \sa WWidget::setStyleClass() */ void useStyleSheet(const WLinkedCssStyleSheet& styleSheet, const std::string& condition = ""); /*! \brief Removes an external stylesheet. * * \sa styleSheet(), useStyleSheet(const std::string&, const std::string&) * \sa WWidget::setStyleClass() */ void removeStyleSheet(const WLink& link); /*! \brief Sets the theme. * * The theme provides the look and feel of several built-in widgets, * using CSS style rules. Rules for each theme are defined in the * resources/themes/theme/ folder. * * The default theme is "default" CSS theme. */ void setTheme(const std::shared_ptr& theme); /*! \brief Returns the theme. */ std::shared_ptr theme() const { return theme_; } /*! \brief Sets a CSS theme. * * This sets a WCssTheme as theme. * * The theme provides the look and feel of several built-in widgets, * using CSS style rules. Rules for each CSS theme are defined in * the resources/themes/name/ folder. * * The default theme is "default". Setting an empty theme "" will * result in a stub CSS theme that does not load any stylesheets. */ void setCssTheme(const std::string& name); /*! \brief Sets the layout direction. * * The default direction is LayoutDirection::LeftToRight. * * This sets the language text direction, which by itself sets the * default text alignment and reverse the column orders of <table> * elements. * * In addition, %Wt will take this setting into account in * WTextEdit, WTableView and WTreeView (so that columns are * reverted), and swap the behaviour of WWidget::setFloatSide() and * WWidget::setOffsets() for LayoutDirection::RightToLeft * languages. Note that CSS settings themselves are not affected by * this setting, and thus for example "float: right" will * move a box to the right, irrespective of the layout direction. * * The library sets "Wt-ltr" or "Wt-rtl" as style * classes for the document body. You may use this if to override * certain style rules for a Right-to-Left document. * * The only valid values are LayoutDirection::LeftToRight or * LayoutDirection::RightToLeft. * * For example: * \code * body .sidebar { float: right; } * body.Wt-rtl .sidebar { float: left; } * \endcode * * \note The layout direction can be set only at application startup * and does not have the effect of rerendering the entire UI. */ void setLayoutDirection(LayoutDirection direction); /*! \brief Returns the layout direction. * * \sa setLayoutDirection() */ LayoutDirection layoutDirection() const { return layoutDirection_; } /*! \brief Sets a style class to the entire page <body>. * * \sa setHtmlClass() */ void setBodyClass(const std::string& styleClass); /*! \brief Returns the style class set for the entire page <body>. * * \sa setBodyClass() */ std::string bodyClass() const { return bodyClass_; } /*! \brief Sets a style class to the entire page <html>. * * \sa setBodyClass() */ void setHtmlClass(const std::string& styleClass); /*! \brief Returns the style class set for the entire page <html>. * * \sa setHtmlClass() */ std::string htmlClass() const { return htmlClass_; } //!@} /*! \brief Sets the window title. * * Sets the browser window title to \p title. * * The default title is "". * * \sa title() */ void setTitle(const WString& title); /*! \brief Returns the window title. * * \sa setTitle(const WString&) */ const WString& title() const { return title_; } /*! \brief Returns the close message. * * \sa setConfirmCloseMessage() */ const WString& closeMessage() const { return closeMessage_; } /*! \brief Returns the resource object that provides localized strings. * * \if cpp * The default value is a WMessageResourceBundle instance, which * uses XML files to resolve localized strings, but you can set a * custom class using setLocalizedStrings(). * \elseif java * This returns the object previously set using setLocalizedStrings(). * \endif * * WString::tr() is used to create localized strings, whose * localized translation is looked up through this object, using a * key. * * \if cpp * \sa WString::tr(), messageResourceBundle() * \elseif java * \sa WString::tr() * \endif */ std::shared_ptr localizedStrings(); #ifdef WT_TARGET_JAVA /*! \brief Accesses the built-in resource bundle. * * This is an internal function and should not be called directly. * * \sa localizedStrings() */ #endif // WT_TARGET_JAVA WMessageResourceBundle& builtinLocalizedStrings(); /*! \brief Sets the resource object that provides localized strings. * * The \p translator resolves localized strings within the current * application locale. * * \sa localizedStrings(), WString::tr(const char *key) */ void setLocalizedStrings(const std::shared_ptr& stringResolver); #ifndef WT_TARGET_JAVA /*! \brief Returns the message resource bundle. * * The message resource bundle defines the list of external XML * files that are used to lookup localized strings. * * The default localizedStrings() is a WMessageResourceBundle * object, and this method returns localizedStrings() downcasted to * this type. * * \throws WException when localizedStrings() is not a WMessageResourceBundle * * \sa WString::tr(const char *key) */ WMessageResourceBundle& messageResourceBundle(); #endif // WT_TARGET_JAVA /*! \brief Changes the locale. * * The locale is used by the localized strings resource to resolve * localized strings. * * By passing an empty \p locale, the default locale is * chosen. * * When the locale is changed, refresh() is called, which will * resolve the strings of the current user-interface in the new * locale. * * At construction, the locale is copied from the environment * (WEnvironment::locale()), and this is the locale that was * configured by the user in his browser preferences, and passed * using an HTTP request header. * * \sa localizedStrings(), WString::tr() */ void setLocale(const WLocale& locale); /*! \brief Returns the current locale. * * \sa setLocale(const WLocale&) */ const WLocale& locale() const { return locale_; } /*! \brief Refreshes the application. * * This lets the application refresh its data, including strings * from message resource bundles. This is done by propagating * WWidget::refresh() through the widget hierarchy. * * This method is also called when the user hits the refresh (or * reload) button, if this can be caught within the current session. * * \if cpp * * The reload button may only be caught when %Wt is configured so that * reload should not spawn a new session. When URL rewriting is used for * session tracking, this will cause an ugly session ID to be added to the * URL. See \ref config_session for configuring the reload * behavior (""). * * \elseif java * * The reload button may only be caught when cookies for session * tracking are configured in the servlet container. * * \endif * * \sa WWidget::refresh() */ virtual void refresh(); /*! \brief Binds a top-level widget for a EntryPointType::WidgetSet deployment. * * This method binds a \p widget to an existing element with DOM id * \p domId on the page. The element type should correspond with * the widget type (e.g. it should be a <div> for a * WContainerWidget, or a <table> for a WTable). * * \sa root() * \sa Wt::EntryPointType::WidgetSet */ void bindWidget(std::unique_ptr widget, const std::string& domId); /** @name URLs and internal paths */ //!@{ /*! \brief Returns a URL for the current session * * Returns the (relative) URL for this application session * (including the session ID if necessary). The URL includes the * full application path, and is expanded by the browser into a full * URL. * * For example, for an application deployed at \code * http://www.mydomain.com/stuff/app.wt \endcode this method might * return "/stuff/app.wt?wtd=AbCdEf". Additional query * parameters can be appended in the form of * "¶m1=value¶m2=value". * * To obtain a URL that is suitable for bookmarking the current * application state, to be used across sessions, use bookmarkUrl() * instead. * * \sa redirect(), WEnvironment::hostName(), WEnvironment::urlScheme() * \sa bookmarkUrl() */ std::string url(const std::string& internalPath = std::string()) const; /*! \brief Makes an absolute URL. * * Returns an absolute URL for a given (relative url) by including * the schema, hostname, and deployment path. * * If \p url is "", then the absolute base URL is returned. This is * the absolute URL at which the application is deployed, up to the * last '/'. * * The default implementation is not complete: it does not handle relative * URL path segments with '..'. It just handles the cases that are necessary for * %Wt. * * This is not used in the library, except when a public URL is * needed, e.g. for inclusion in an email. * * You may want to reimplement this method when the application is * hosted behind a reverse proxy or in general the public URL of the * application cannot be guessed correctly by the application. */ virtual std::string makeAbsoluteUrl(const std::string& url) const; /*! \brief "Resolves" a relative URL taking into account internal paths. * * This resolves the relative URL against the base path of the application, * so that it will point to the correct path regardless of the current internal * path, e.g. if the application is deployed at %http://example.com/one * and we're at the internal path /two/, so that the full URL is * %http://example.com/one/two/, the output of the input URL three * will point to %http://example.com/three, and not * %http://example.com/one/two/three. * * If the given url is the empty string, the result will point to the base path * of the application. * * See the table below for more examples. * *

When you would want to use resolveRelativeUrl:

* * Using HTML5 History API or in a plain HTML session (without ugly * internal paths), the internal path is present as a full part of * the URL. This has a consequence that relative URLs, if not dealt * with, would be resolved against the last 'folder' name of the * internal path, rather than against the application deployment * path (which is what you probably want). * * When using a widgetset mode deployment, or when configuring a * baseURL property in the configuration, this method will make an * absolute URL so that the property is fetched from the right * server. * * Otherwise, this method will fixup a relative URL so that it * resolves correctly against the base path of an application. This * does not necessarily mean that the URL is resolved into an * absolute URL. In fact, %Wt will simply prepend a sequence of "../" * path elements to correct for the internal path. When passed an * absolute URL (i.e. starting with '/'), the url is returned * unchanged. * * For URLs passed to the %Wt API (and of which the library knows it * represents a URL) this method is called internally by the * library. But it may be useful for URLs which are set e.g. inside * a WTemplate. * *

Examples

* * Note that whether the deployment path and entry point ends with a slash is significant. * Below are some examples with the * deployment path in red * and the internal path in blue. * * * * * * * * * * * * * *
Current full pathurl argumentResult points to
%http://example.com/foo/bar/internal/path
Deployment path: /foo/bar (no slash at the end)
Internal path: /internal/path
(empty string)%http://example.com/foo/bar
.%http://example.com/foo/
./%http://example.com/foo/
../%http://example.com/
%http://example.com/foo/bar/internal/path
Deployment path: /foo/bar/ (with slash at the end)
Internal path: /internal/path
Note that the slash between the deployment path and the internal path is shared
(empty string)%http://example.com/foo/bar/
.%http://example.com/foo/bar/
./%http://example.com/foo/bar/
../%http://example.com/foo/
*/ std::string resolveRelativeUrl(const std::string& url) const; /*! \brief Returns a bookmarkable URL for the current internal path. * * Is equivalent to bookmarkUrl(internalPath()), see * bookmarkUrl(const std::string&) const. * * To obtain a URL that is refers to the current session of the * application, use url() instead. * * \sa url(), bookmarkUrl(const std::string&) const */ std::string bookmarkUrl() const; /*! \brief Returns a bookmarkable URL for a given internal path. * * Returns the (relative) URL for this application that includes the * internal path \p internalPath, usable across sessions. * * The returned URL concatenates the internal path to the application * base URL, and when no JavaScript is available and URL rewriting is used * for session-tracking, a session Id is appended to reuse an existing * session if available. * * \if cpp * See also \ref config_session for configuring the session-tracking * method. * * For the built-in httpd, when the application is deployed at a folder * (ending with '/'), only an exact matching path is routed to * the application (this can be changed since Wt 3.1.9, see * \ref wthttpd ), making clean URLs impossible. Returned URLs then * include a "?_=" encoding for the internal path. * \endif * * You can use bookmarkUrl() as the destination for a WAnchor, and * listen to a click event is attached to a slot that switches to * the internal path \p internalPath (see * WAnchor::setRefInternalPath()). In this way, an anchor can be * used to switch between internal paths within an application * regardless of the situation (browser with or without Ajax * support, or a web spider bot), but still generates suitable URLs * across sessions, which can be used for bookmarking, opening in a * new window/tab, or indexing. * * To obtain a URL that refers to the current session of the * application, use url() instead. * * \sa url(), bookmarkUrl() * * \if cpp * \note the \p internalPath should be CharEncoding::UTF8 encoded (we may fix the API * to use WString in the future). * \endif */ std::string bookmarkUrl(const std::string& internalPath) const; /*! \brief Changes the internal path. * * A %Wt application may manage multiple virtual paths. The virtual * path is appended to the application URL. Depending on the * situation, the path is directly appended to the application URL * or it is appended using a name anchor (#). * * For example, for an application deployed at: * \code * http://www.mydomain.com/stuff/app.wt * \endcode * for which an \p internalPath "/project/z3cbc/details/" is * set, the two forms for the application URL are: *
    *
  • in an AJAX session (HTML5): * \code * http://www.mydomain.com/stuff/app.wt/project/z3cbc/details/ * \endcode *
  • in an AJAX session (HTML4): * \code * http://www.mydomain.com/stuff/app.wt#/project/z3cbc/details/ * \endcode *
  • * in a plain HTML session: * \code * http://www.mydomain.com/stuff/app.wt/project/z3cbc/details/ * \endcode *
* * Note, since %Wt 3.1.9, the actual form of the URL no longer * affects relative URL resolution, since now %Wt includes an HTML * meta base tag which points to the deployment path, * regardless of the current internal path. This does break * deployments behind a reverse proxy which changes paths. * * \if cpp * For the built-in httpd, when the application is deployed * at a folder (ending with '/'), only an exact matching path is * routed to the application (this can be changed since Wt 3.1.9, * see \ref wthttpd ), making clean URLs impossible. Returned * URLs then include a "?_=" encoding for the internal * path: * * \code * http://www.mydomain.com/stuff/?_=/project/z3cbc/details/ * \endcode * \endif * * When the internal path is changed, an entry is added to the * browser history. When the user navigates back and forward through * this history (using the browser back/forward buttons), an * internalPathChanged() event is emitted. You should listen to this * signal to switch the application to the corresponding state. When * \p emitChange is \c true, this signal is also emitted by setting * the path (but only if the path is actually changed). * * A url that includes the internal path may be obtained using * bookmarkUrl(). * * The \p internalPath must start with a '/'. In this way, you * can still use normal anchors in your HTML. Internal path changes * initiated in the browser to paths that do not start with a '/' * are ignored. * * The \p emitChange parameter determines whether calling this * method causes the internalPathChanged() signal to be emitted. * * \sa bookmarkUrl(), internalPath(), internalPathChanged() * * \if cpp * \note the \p path should be CharEncoding::UTF8 encoded (we may fix the API * to use WString in the future). * \endif */ void setInternalPath(const std::string& path, bool emitChange = false); /*! \brief Sets whether an internal path is valid by default. * * This configures how you treat (invalid) internal paths. If an * internal path is treated valid by default then you need to call * setInternalPath(false) for an invalid path. If on the other hand * you treat an internal path as invalid by default, then you need * to call setInternalPath(true) for a valid path. * * A user which opens an invalid internal path will receive a HTTP * 404-Not Found response code (if sent an HTML response). * * The default value is \c true. */ void setInternalPathDefaultValid(bool valid); /*! \brief Returns whether an internal path is valid by default. * * \sa setInternalPathDefaultValid() */ bool internalPathDefaultValid() const { return internalPathDefaultValid_; } /*! \brief Sets whether the current internal path is valid. * * You can use this function in response to an internal path change * event (or at application startup) to indicate whether the new (or * initial) internal path is valid. This has only an effect on plain * HTML sessions, or on the first response in an application * deployed with progressive bootstrap settings, as this generates * then a 404 Not-Found response. * * \sa internalPathChanged(), setInternalPathDefaultValid() */ void setInternalPathValid(bool valid); /*! \brief Returns whether the current internal path is valid. * * \sa setInternalPathValid() */ bool internalPathValid() const { return internalPathValid_; } /*! \brief Returns the current internal path. * * When the application is just created, this is equal to * WEnvironment::internalPath(). * * \sa setInternalPath(), internalPathNextPart(), internalPathMatches() * * \if cpp * \note the \p returned path is CharEncoding::UTF8 (we may fix the API * to use WString in the future). * \endif */ std::string internalPath() const; /*! \brief Returns a part of the current internal path. * * This is a convenience method which returns the next \p folder * in the internal path, after the given \p path. * * For example, when the current internal path is * "/project/z3cbc/details", this method returns * "details" when called with "/project/z3cbc/" as * \p path argument. * * The \p path must start with a '/', and internalPathMatches() * should evaluate to \c true for the given \p path. If not, * an empty string is returned and an error message is logged. * * \sa internalPath(), internalPathChanged() * * \if cpp * \note the \p internal path is CharEncoding::UTF8 encoded (we may fix the API * to use WString in the future). * \endif */ std::string internalPathNextPart(const std::string& path) const; std::string internalSubPath(const std::string& path) const; /*! \brief Checks if the internal path matches a given path. * * Returns whether the current internalPath() starts with * \p path (or is equal to \p path). You will typically use * this method within a slot conneted to the internalPathChanged() * signal, to check that an internal path change affects the * widget. It may also be useful before changing \p path using * setInternalPath() if you do not intend to remove sub paths when * the current internal path already matches \p path. * * The \p path must start with a '/'. * * \sa setInternalPath(), internalPath() * * \if cpp * \note the \p internal path is CharEncoding::UTF8 encoded (we may fix the API * to use WString in the future). * \endif */ bool internalPathMatches(const std::string& path) const; /*! \brief %Signal which indicates that the user changes the internal path. * * This signal indicates a change to the internal path, which is * usually triggered by the user using the browser back/forward * buttons. * * The argument contains the new internal path. * * \sa setInternalPath() * * \if cpp * \note the \p internal path is CharEncoding::UTF8 encoded (we may fix the API * to use WString in the future). * \endif */ Signal& internalPathChanged(); /*! \brief %Signal which indicates that an invalid internal path is navigated. */ Signal& internalPathInvalid() { return internalPathInvalid_; } /*! \brief Redirects the application to another location. * * The client will be redirected to a new location identified by \p * url. Use this in conjunction with quit() if you want the * application to be terminated as well. * * Calling %redirect() does not imply %quit() since it may be useful * to switch between a non-secure and secure (SSL) transport * connection. */ void redirect(const std::string& url); //!@} /*! \brief Returns the URL at which the resources are deployed. * * Returns resolveRelativeUrl(relativeResourcesUrl()) */ static std::string resourcesUrl(); /*! \brief Returns the URL at which the resources are deployed. * * \if cpp * This returns the value of the 'resources' property set in the * configuration file, and may thus be a URL relative to the deployment * path. * \endif * * \sa resolveRelativeUrl() */ static std::string relativeResourcesUrl(); #ifndef WT_TARGET_JAVA /*! \brief Returns the appRoot special property * * This returns the "appRoot" property, with a trailing slash added * to the end if it was not yet present. * * The property "appRoot" was introduced as a generalization of the * working directory for the location of files that do not need to * be served over http to the client, but are required by the * program to run properly. Typically, these are message resource * bundles (xml), CSV files, database files (e.g. SQLite files for * Wt::Dbo), ... * * Some connectors do not allow you to control what the current * working directory (CWD) is set to (fcgi, isapi). Instead of * referring to files assuming a sensible CWD, it is therefore * better to refer to them relative to the application root. * * The appRoot property is special in the sense that it can be set * implicitly by the connector (see the connector documentation for * more info). If it was not set by the connector, it can be set as * a normal property in the configuration file (the default * wt_config.xml describes how to set properties). If the property * is not set at all, it is assumed that the appRoot is CWD and this * function will return an empty string. * * \if cpp * Usage example: * \code * messageResourceBundle().use(appRoot() + "text"); * messageResourceBundle().use(appRoot() + "charts"); * * auto sqlite3_ = std::make_unique(appRoot() + "planner.db"); * \endcode * \endif * * \sa WServer::appRoot(), docRoot() */ static std::string appRoot(); /*! \brief Returns the server document root. * * This returns the filesystem path that corresponds to the document root * of the webserver. * * \note This does not work reliably for complex webserver configurations * (e.g. using FastCGI with Apache and rewrite rules). See also the * * discussion here. * * \sa appRoot() */ std::string docRoot() const; /*! \brief Sets a client-side connection monitor * * This can be used to be notified, in the browser, of changes in * connection state between the browser and the server. The passed * \p jsObject should be an object that has the following prototype: * \code * { * onChange: function(type, oldValue, newValue) { ... } * } * \endcode * * The 'onChange' function will be called on an connection status change * event. The following types are defined: * - "connectionStatus": 0 = disconnected, 1 = connected * - "websocket": true = websocket is used, false = websocket is not used * * The current state is also stored in a 'status' object inside the * connection monitor. * * Example usage: * \code * app.setConnectionMonitor("{ onChange: function(type, ov, nv) { console.log(type, ov, nv); } }"); * \endcode */ void setConnectionMonitor(const std::string& jsObject); #else static std::string appRoot(); #endif // WT_TARGET_JAVA /*! \brief Returns the unique identifier for the current session. * * The session id is a string that uniquely identifies the current session. * Note that the actual contents has no particular meaning and client * applications should in no way try to interpret its value. */ std::string sessionId() const; #ifndef WT_TARGET_JAVA /*! \brief Changes the session id. * * To mitigate session ID fixation attacks, you should use this * method to change the session ID to a new random value after a * user has authenticated himself. * * \sa sessionId() */ void changeSessionId(); #endif // WT_TARGET_JAVA WebSession *session() const { return session_; } /** @name Manipulation outside the main event loop */ //!@{ /*! \brief Enables server-initiated updates. * * By default, updates to the user interface are possible only at * startup, during any event (in a slot), or at regular time points * using WTimer. This is the normal %Wt event loop. * * In some cases, one may want to modify the user interface from a * second thread, outside the event loop. While this may be worked * around by the WTimer, in some cases, there are bandwidth and * processing overheads associated which may be unnecessary, and * which create a trade-off with time resolution of the updates. * * When \p enabled is \c true, this enables "server push" (what is * called 'comet' in AJAX terminology). Widgets may then be * modified, created or deleted outside of the event loop (e.g. in * response to execution of another thread), and these changes are * propagated by calling triggerUpdate(). * * \if cpp * There are two ways for safely manipulating a session's UI, with * respect to thread-safety and application life-time (the library * can decide to terminate an application if it lost connectivity * with the browser). * *

WServer::post()

* * The easiest and less error-prone solution is to post an event, * represented by a function/method call, to a session using * WServer::post(). * * The method is non-blocking: it returns immediately, avoiding * dead-lock scenarios. The function is called from within a thread * of the server's thread pool, and not if the session has been or * is being terminated. The function is called in the context of the * targeted application session, and with exclusive access to the * session. * *

WApplication::UpdateLock

* * A more direct approach is to grab the application's update lock and * manipulate the application's state directly from another thread. * * At any time, the application may be deleted (e.g. because of a * time out or because the user closes the application window). You * should thus make sure you do no longer reference an application * after it has been deleted. When %Wt decides to delete an * application, it first runs WApplication::finalize() and then * invokes the destructor. While doing this, any other thread trying * to grab the update lock will unblock, but the lock will return \c * false. You should therefore always check whether the lock is * valid. * * \elseif java * * Note that you need to grab the application's update lock to avoid * concurrency problems, whenever you modify the application's state * from another thread. * * \endif * * An example of how to modify the widget tree outside the event loop * and propagate changes is: * \if cpp * \code * // You need to have a reference to the application whose state * // you are about to manipulate. * // You should prevent the application from being deleted somehow, * // before you could grab the application lock. * Wt::WApplication *app = ...; * * { * // Grab the application lock. It is a scoped lock. * Wt::WApplication::UpdateLock lock(app); * * if (lock) { * // We now have exclusive access to the application: we can safely modify the widget tree for example. * app->root()->addWidget(std::make_unique("Something happened!")); * * // Push the changes to the browser * app->triggerUpdate(); * } * } * \endcode * \elseif java * \code * // You need to have a reference to the application whose state * // you are about to manipulate. * WApplication app = ...; * * // Grab the application lock * WApplication.UpdateLock lock = app.getUpdateLock(); * * try { * // We now have exclusive access to the application: * // we can safely modify the widget tree for example. * app.getRoot().addWidget(new WText("Something happened!")); * * // Push the changes to the browser * app.triggerUpdate(); * } finally { * lock.release(); * } * \endcode * \endif * * \if java * This works only if your servlet container supports the Servlet 3.0 * API. If you try to invoke this function on a servlet container with * no such support, an exception will be thrown. * \endif * * \note This works only if JavaScript is available on the client. * * \sa triggerUpdate() */ void enableUpdates(bool enabled = true); /*! \brief Returns whether server-initiated updates are enabled. * * \sa enableUpdates() */ bool updatesEnabled() const { return serverPush_ > 0; } /*! \brief Propagates server-initiated updates. * * When the lock to the application is released, changes will * propagate to the user interface. This call only has an effect * after updates have been enabled from within the normal event loop * using enableUpdates(). * * This is typically used only outside of the main event loop, * e.g. from another thread or from within a method posted to an * application using WServer::post(), since changes always propagate * within the event loop at the end of the event. * * The update is not immediate, and thus changes that happen after this * call will equally be pushed to the client. * * \sa enableUpdates() */ void triggerUpdate(); #ifndef WT_TARGET_JAVA /*! \brief A RAII lock for manipulating and updating the * application and its widgets outside of the event loop. * * You can use this lock to manipulate widgets outside of the event * loop. Inside the event loop (including events posted using * WServer::post()), this lock is already held by the library itself. * * The lock is recursive, so trying to take a lock, while already * holding a lock, will not block. */ #else /*! \brief A synchronization lock for manipulating and updating the * application and its widgets outside of the event loop. * * You need to take this lock only when you want to manipulate * widgets outside of the event loop. LabelOption::Inside the event loop, this * lock is already held by the library itself. * * \sa getUpdateLock() */ #endif // WT_TARGET_JAVA class WT_API UpdateLock #ifdef WT_TARGET_JAVA : public AutoCloseable #endif // WT_TARGET_JAVA { public: #ifndef WT_TARGET_JAVA /*! \brief Creates and locks the given application. * * The lock guarantees exclusive access to modify the * application's state. * * You should also consider WServer::post() for lock-free * communication between different application sessions. * * As soon as the library decides to destroy the application, the * lock will no longer succeed in taking the application lock. You * can need to detect this by checking that after the lock is taken, * the lock is taken: * \code * WApplication::UpdateLock lock(app); * if (lock) { * // exclusive access to app state * } * \endcode */ UpdateLock(WApplication *app); /*! \brief Tests whether the update lock was succesfully taken. * * This may return \c false when the library has already decided * to destroy the session (but before your application * finalizer/destructor has run to notify helper threads that the * application is destroyed). */ explicit operator bool() const { return ok_; } /*! \brief Releases the lock. */ ~UpdateLock(); #else /*! \brief Releases the lock. */ void release(); #endif #ifdef WT_TARGET_JAVA /*! \brief Releases the lock. * * Calls release() * * Implemented in order to support the AutoCloseable interface. */ virtual void close(); #endif // WT_TARGET_JAVA private: #ifdef WT_TARGET_JAVA UpdateLock(WApplication *app); bool createdHandler_; #endif // WT_TARGET_JAVA #ifndef WT_TARGET_JAVA mutable std::unique_ptr impl_; bool ok_; #endif // !WT_TARGET_JAVA friend class WApplication; }; #ifdef WT_TARGET_JAVA /*! \brief Grabs and returns the lock for manipulating widgets outside * the event loop. * * You need to keep this lock in scope while manipulating widgets * outside of the event loop. In normal cases, inside the %Wt event * loop, you do not need to care about it. * * \sa enableUpdates(), triggerUpdate() */ UpdateLock getUpdateLock(); #endif // WT_TARGET_JAVA /*! \brief Attach an auxiliary thread to this application. * * In a multi-threaded environment, WApplication::instance() uses * thread-local data to retrieve the application object that * corresponds to the session currently being handled by the * thread. This is set automatically by the library whenever an * event is delivered to the application, or when you use the * UpdateLock to modify the application from an auxiliary thread * outside the normal event loop. * * When you want to manipulate the widget tree inside the main event * loop, but from within an auxiliary thread, then you cannot use * the UpdateLock since this will create an immediate dead * lock. Instead, you may attach the auxiliary thread to the * application, by calling this method from the auxiliary thread, * and in this way you can modify the application from within that * thread without needing the update lock. * * Calling attachThread() with \p attach = \c false, detaches the * current thread. */ void attachThread(bool attach = true); //!@} /** @name Invoking JavaScript or including scripts */ //!@{ /*! \brief Executes some JavaScript code. * * This method may be used to call some custom \p javaScript code as * part of an event response. * * This function does not wait until the JavaScript is run, but * returns immediately. The JavaScript will be run after the normal * event handling, unless \p afterLoaded is set to \c false. * * In most situations, it's more robust to use * WWidget::doJavaScript() however. * * \sa WWidget::doJavaScript(), declareJavaScriptFunction() */ void doJavaScript(const std::string& javascript, bool afterLoaded = true); /*! \brief Adds JavaScript statements that should be run continuously. * * This is an internal method. * * It is used by for example layout managers to adjust the layout * whenever the DOM tree is manipulated. * * \sa doJavaScript() */ void addAutoJavaScript(const std::string& javascript); /*! \brief Declares an application-wide JavaScript function. * * The function is stored in WApplication::javaScriptClass(). * * The next code snippet declares and invokes function foo: * \if cpp * \code * app->declareJavaScriptFunction("foo", * "function(id) { ... }"); * ... * std::string id("myId"); * app->doJavaScript(app->javaScriptClass() + ".foo('" + id + "');"); * \endcode * \endif */ void declareJavaScriptFunction(const std::string& name, const std::string& function); /*! \brief Loads a JavaScript library. * * Loads a JavaScript library located at the URL \p url. %Wt keeps * track of libraries (with the same URL) that already have been * loaded, and will load a library only once. In addition, you may * provide a \p symbol which if already defined will also indicate * that the library was already loaded (possibly outside of %Wt when * in EntryPointType::WidgetSet mode). * * This method returns \c true only when the library is loaded * for the first time. * * JavaScript libraries may be loaded at any point in time. Any * JavaScript code is deferred until the library is loaded, except * for JavaScript that was defined to load before, passing \c false * as second parameter to doJavaScript(). * * Although %Wt includes an off-the-shelf JQuery version (which can * also be used by your own JavaScript code), you can override the * one used by %Wt and load another JQuery version instead, but this * needs to be done using requireJQuery(). */ bool require(const std::string& url, const std::string& symbol = std::string()); /*! \brief Loads a custom JQuery library. * * %Wt ships with a rather old version of JQuery (1.4.1) which is * sufficient for its needs and is many times smaller than more recent * JQuery releases (about 50% smaller). * * Using this function, you can replace Wt's JQuery version with another * version of JQuery. * * \code * requireJQuery("jquery/jquery-1.7.2.min.js"); * \endcode */ bool requireJQuery(const std::string& url); /*! \brief Returns whether a custom JQuery library is used. * * \sa requireJQuery(const std::string& url) */ bool customJQuery() const { return customJQuery_; } /*! \brief Sets the name of the application JavaScript class. * * This should be called right after construction of the application, and * changing the JavaScript class is only supported for EntryPointType::WidgetSet mode * applications. The \p className should be a valid JavaScript identifier, and * should also be unique in a single page. */ void setJavaScriptClass(const std::string& className); /*! \brief Returns the name of the application JavaScript class. * * This JavaScript class encapsulates all JavaScript methods * specific to this application instance. The method is foreseen to * allow multiple applications to run simultaneously on the same * page in Wt::WidgtSet mode, without interfering. */ std::string javaScriptClass() { return javaScriptClass_; } //!@} /*! \brief Processes UI events. * * You may call this method during a long operation to: * - propagate widget changes to the client. * - process UI events. * * This method starts a recursive event loop, blocking the current * thread, and resumes when all pending user interface events have been * processed. * * Because a thread is blocked, this may affect your application * scalability. */ void processEvents(); /*! \brief Blocks the thread, waiting for an UI event. * * This function is used by functions like WDialog::exec() or * WPopupMenu::exec(), to block the current thread waiting for a new * event. * * This requires that at least one additional thread is available to * process incoming requests, and is not scalable when working with * a fixed size thread pools. */ virtual void waitForEvent(); #ifndef WT_TARGET_JAVA /*! \brief Reads a configuration property. * * Tries to read a configured value for the property * \p name. The method returns whether a value is defined for * the property, and sets it to \p value. * * \sa WServer::readConfigurationProperty() */ static bool readConfigurationProperty(const std::string& name, std::string& value); #else /*! \brief Reads a configuration property. * * Tries to read a configured value for the property * \p name. If no value was configured, the default \p value * is returned. */ static std::string *readConfigurationProperty(const std::string& name, const std::string& value); #endif // WT_TARGET_JAVA /* * The DOM root object. This contains not only the application root but * also other invisible objects (timers, dialog covers, ...). */ WWebWidget *domRoot() const; /* * A phony DOM root object, used to logically contain all widgets bound * in widgetset mode. */ WContainerWidget *domRoot2() const { return domRoot2_.get(); } /* * Encode an object to a string, to make it referencable from JavaScript. * Currently only used to encode the drag object in drag & drop. * * FIXME: provide a way to remove the encoding! * * \see decodeObject() */ std::string encodeObject(WObject *object); /* * Decode an object. * * \see encodeObject() */ WObject *decodeObject(const std::string& objectId) const; #ifndef WT_TARGET_JAVA /*! \brief Initializes the application, post-construction. * * This method is invoked by the %Wt library after construction of a * new application. You may reimplement this method to do additional * initialization that is not possible from the constructor * (e.g. which uses virtual methods). */ virtual void initialize(); /*! \brief Finalizes the application, pre-destruction. * * This method is invoked by the %Wt library before destruction of a * new application. You may reimplement this method to do additional * finalization that is not possible from the destructor (e.g. which * uses virtual methods). */ virtual void finalize(); #else /*! \brief Destroys the application session. * * The application is destroyed when the session is invalidated. You * should put here any logic which is needed to cleanup the * application session. * * The default implementation does nothing. */ virtual void destroy(); #endif //WT_TARGET_JAVA /*! \brief Changes the threshold for two-phase rendering. * * This changes the threshold for the \p size of a JavaScript * response (in bytes) to render invisible changes in one go. If the * bandwidth for rendering the invisible changes exceed the * threshold, they will be fetched in a second communication, after * the visible changes have been rendered. * * The value is a trade-off: setting it smaller will always use * two-phase rendering, increasing the total render time but * reducing the latency for the visible changes. Setting it too * large will increase the latency to render the visible changes, * since first also all invisible changes need to be computed and * received in the browser. * * \if cpp * The initial value is read from the configuration file, see \ref * config_general. * \endif */ void setTwoPhaseRenderingThreshold(int size); /*! \brief Sets a new cookie. * * Use cookies to transfer information across different sessions * (e.g. a user name). In a subsequent session you will be able to * read this cookie using WEnvironment::getCookie(). You cannot use * a cookie to store information in the current session. * * The name must be a valid cookie name (of type 'token': no special * characters or separators, see RFC2616 page 16). The value may be * anything. Specify the maximum age (in seconds) after which the * client must discard the cookie. To delete a cookie, use a value of '0'. * * By default the cookie only applies to the application deployment * path (WEnvironment::deploymentPath()) in the current domain. To * set a proper value for domain, see also RFC2109. * * \if cpp * \note %Wt provides session tracking automatically, and may be configured * to use a cookie for this. You only need to use cookies yourself * if you want to remember some information (like a logged in identity) * across sessions. * \endif * * \sa WEnvironment::supportsCookies(), WEnvironment::getCookie() */ void setCookie(const std::string& name, const std::string& value, int maxAge, const std::string& domain = "", const std::string& path = "", bool secure = false); #ifndef WT_TARGET_JAVA void setCookie(const std::string& name, const std::string& value, const WDateTime& expires, const std::string& domain = "", const std::string& path = "", bool secure = false); #endif // WT_TARGET_JAVA /*! \brief Removes a cookie. * * \sa setCookie() */ void removeCookie(const std::string& name, const std::string& domain = "", const std::string& path = ""); /*! \brief Adds an HTML meta link. * * When a link was previously set for the same \p href, its contents * are replaced. * When an empty string is used for the arguments \p media, \p hreflang, * \p type or \p sizes, they will be ignored. * * \sa removeMetaLink() */ void addMetaLink(const std::string &href, const std::string &rel, const std::string &media, const std::string &hreflang, const std::string &type, const std::string &sizes, bool disabled); /*! \brief Removes the HTML meta link. * * \sa addMetaLink() */ void removeMetaLink(const std::string &href); /*! \brief Adds a "name" HTML meta header. * * \sa addMetaHeader(MetaHeaderType, const std::string&, const WString&, const std::string&) */ void addMetaHeader(const std::string& name, const WString& content, const std::string& lang = ""); /*! \brief Adds an HTML meta header. * * This method sets either a "name" meta headers, which configures a * document property, or a "http-equiv" meta headers, which defines * a HTTP headers (but these latter headers are being deprecated). * * A meta header can however only be added in the following situations: * * - when a plain HTML session is used (including when the user agent is a * bot), you can add meta headers at any time. * - or, when \ref progressive_bootstrap "progressive bootstrap" is * used, you can set meta headers for any type of session, from * within the application constructor (which corresponds to the * initial request). * - but never for a Wt::EntryPointType::WidgetSet mode application since then the * application is hosted within a foreign HTML page. * * These situations coincide with WEnvironment::ajax() returning \c * false (see environment()). The reason that it other cases the * HTML page has already been rendered, and will not be rerendered * since all updates are done dynamically. * * As an alternative, you can use the <meta-headers> * configuration property in the configuration file, which will be * applied in all circumstances. * * \sa removeMetaHeader() */ void addMetaHeader(MetaHeaderType type, const std::string& name, const WString& content, const std::string& lang = ""); /*! \brief Returns a meta header value. * * \sa addMetaHeader() */ WString metaHeader(MetaHeaderType type, const std::string& name) const; /*! \brief Removes one or all meta headers. * * Removes the meta header with given type and name (if it is present). * If name is empty, all meta headers of the given type are removed. * * \sa addMetaHeader() */ void removeMetaHeader(MetaHeaderType type, const std::string& name = ""); #ifndef WT_TARGET_JAVA /*! \brief Adds an entry to the application log. * * Starts a new log entry of the given \p type in the %Wt * application log file. This method returns a stream-like object to * which the message may be streamed. * * \if cpp * A typical usage would be: * \code * wApp->log("notice") << "User " << userName << " logged in successfully."; * \endcode * * This would create a log entry that looks like: * \verbatim [2008-Jul-13 14:01:17.817348] 16879 [/app.wt Z2gCmSxIGjLHD73L] [notice] "User bart logged in successfully." * \endverbatim * \endif * * \if cpp * \sa \ref config_general * \endif */ WLogEntry log(const std::string& type) const; #endif // WT_TARGET_JAVA /*! \brief Sets the loading indicator. * * The loading indicator is shown to indicate that a response from * the server is pending or JavaScript is being evaluated. * * The default loading indicator is a WDefaultLoadingIndicator. */ void setLoadingIndicator(std::unique_ptr indicator); /*! \brief Returns the loading indicator. * * \sa setLoadingIndicator() */ WLoadingIndicator *loadingIndicator() const { return loadingIndicator_; } /* * A url to a resource that provides a one pixel gif. This is sometimes * useful for CSS hackery to make IE behave. */ std::string onePixelGifUrl(); /* * The doctype used to deliver the application. */ std::string docType() const; /*! \brief Quits the application. * * This quits the application with a default restart message resolved * as WString::tr("Wt.QuittedMessage"). * * \sa quit(const WString&) */ void quit(); /*! \brief Quits the application. * * The method returns immediately, but has as effect that the * application will be terminated after the current event is * completed. * * The current widget tree (including any modifications still * pending and applied during the current event handling) will still * be rendered, after which the application is terminated. * * If the restart message is not empty, then the user will be * offered to restart the application (using the provided message) * when further interacting with the application. * * \sa redirect() */ void quit(const WString& restartMessage); /*! \brief Returns whether the application has quit. * * \sa quit() */ bool hasQuit() const { return quitted_; } /*! \brief Returns the current maximum size of a request to the * application. * * The returned value is the maximum request size in bytes. * * \if cpp * The maximum request size is configured in the configuration file, * see \ref config_general. * \endif * * \sa requestTooLarge() */ ::int64_t maximumRequestSize() const; /*! \brief %Signal which indicates that too a large request was received. * * The integer parameter is the request size that was received in bytes. */ Signal< ::int64_t>& requestTooLarge() { return requestTooLarge_; } /** @name Global keyboard and mouse events */ //!@{ /*! \brief Event signal emitted when a keyboard key is pushed down. * * The application receives key events when no widget currently * has focus. Otherwise, key events are handled by the widget in focus, * and its ancestors. * * \sa See WInteractWidget::keyWentDown() */ EventSignal& globalKeyWentDown(); /*! \brief Event signal emitted when a "character" was entered. * * The application receives key events when no widget currently * has focus. Otherwise, key events are handled by the widget in focus, * and its ancestors. * * \sa See WInteractWidget::keyPressed() */ EventSignal& globalKeyPressed(); /*! \brief Event signal emitted when a keyboard key is released. * * The application receives key events when no widget currently * has focus. Otherwise, key events are handled by the widget in focus, * and its ancestors. * * \sa See WInteractWidget::keyWentUp() */ EventSignal& globalKeyWentUp(); /*! \brief Event signal emitted when enter was pressed. * * The application receives key events when no widget currently * has focus. Otherwise, key events are handled by the widget in focus, * and its ancestors. * * \sa See WInteractWidget::enterPressed() */ EventSignal<>& globalEnterPressed(); /*! \brief Event signal emitted when escape was pressed. * * The application receives key events when no widget currently * has focus. Otherwise, key events are handled by the widget in focus, * and its ancestors. * * \sa See WInteractWidget::escapePressed() */ EventSignal<>& globalEscapePressed(); //!@} /* * Returns whether debug was configured. * (should be public API ?) */ bool debug() const; /* * Methods for client-side focus */ void setFocus(const std::string& id, int selectionStart, int selectionEnd); #ifdef WT_DEBUG_JS void loadJavaScript(const char *jsFile); #else #ifdef WT_TARGET_JAVA /*! \brief Loads an internal JavaScript file. * * This is an internal function and should not be called directly. * * \sa require(), doJavaScript() */ #endif void loadJavaScript(const char *jsFile, const WJavaScriptPreamble& preamble); #endif bool javaScriptLoaded(const char *jsFile) const; /*! \brief Sets the message for the user to confirm closing of the * application window/tab. * * If the message is empty, then the user may navigate away from the page * without confirmation. * * Otherwise the user will be prompted with a browser-specific * dialog asking him to confirm leaving the page. This \p message is * added to the page. * * \sa unload() */ void setConfirmCloseMessage(const WString& message); void enableInternalPaths(); // should we move this into an InternalPaths utility class / namespace ? #ifdef WT_TARGET_JAVA /*! \brief Utility function to check if one path falls under another path. * * This returns whether the \p query path matches the given \p path, * meaning that it is equal to that path or it specifies a more * specific sub path of that path. */ #endif // WT_TARGET_JAVA static bool pathMatches(const std::string& path, const std::string& query); #ifndef WT_TARGET_JAVA /*! \brief Defers rendering of the current event response. * * This method defers the rendering of the current event response * until resumeRendering() is called. This may be used if you do not * want to actively block the current thread while waiting for an * event which is needed to complete the current event * response. Note that this effectively freezes the user interface, * and thus you should only do this if you know that the event you * are waiting for will arrive shortly, or there is really nothing more * useful for the user to do than wait for the action to complete. * * A typical use case is in conjunction with the Http::Client, to * defer the rendering while waiting for the Http::Client to * complete. * * The function may be called multiple times and the number of deferral * requests is counted. The current response is deferred until as * many calls to resumeRendering() have been performed. * * \sa resumeRendering() */ void deferRendering(); /*! \brief Resumes rendering of a deferred event response. * * \sa deferRendering() */ void resumeRendering(); #endif /*! \brief Encodes an untrusted URL to prevent referer leaks. * * This encodes an URL so that in case the session ID is present * in the current URL, this session ID does not leak to the refenced * URL. * * %Wt will safely handle URLs in the API (in WImage and WAnchor) but * you may want to use this function to encode URLs which you use in * WTemplate texts. */ std::string encodeUntrustedUrl(const std::string& url) const; /*! \brief Pushes a (modal) widget onto the expose stack. * * This defines a new context of widgets that are currently visible. */ void pushExposedConstraint(WWidget *w); void popExposedConstraint(WWidget *w); void addGlobalWidget(WWidget *w); // from within constructor void removeGlobalWidget(WWidget *w); // from within destructor protected: /*! \brief Notifies an event to the application. * * This method is called by the event loop for propagating an event * to the application. It provides a single point of entry for * events to the application, besides the application constructor. * * You may want to reimplement this method for two reasons: * * - for having a single point for exception handling: while you may want * to catch recoverable exceptions in a more appropriate place, general * (usually fatal) exceptions may be caught here. You will probably * want to catch the same exceptions in the application constructor * in the same way. * - you want to manage resource usage during requests. For example, at * the end of request handling, you want to return a database session * back to the pool. Since %notify() is also used for rendering right after * the application is created, this will also clean up resources after * application construction. * * In either case, you will need to call the base class * implementation of %notify(), as otherwise no events will be * delivered to your application. * * The following shows a generic template for reimplementhing this * method for both managing request resources and generic exception * handling. * * \if cpp * \code * MyApplication::notify(const WEvent& event) * { * // Grab resources for during request handling * try { * WApplication::notify(event); * } catch (MyException& exception) { * // handle this exception in a central place * } * // Free resources used during request handling * } * \endcode * \elseif java * \code * void notify(WEvent event) { * // Grab resources for during request handling * try { * super.notify(event); * } catch (MyException exception) { * // handle this exception in a central place * } * // Free resources used during request handling * } * \endcode * \endif * * Note that any uncaught exception throw during event handling * terminates the session. */ virtual void notify(const WEvent& e); /*! \brief Returns whether a widget is exposed in the interface. * * The default implementation simply returns \c true, unless a modal * dialog is active, in which case it returns \c true only for widgets * that are inside the dialog. * * You may want to reimplement this method if you wish to disallow * events from certain widgets even when they are inserted in the * widget hierachy. */ virtual bool isExposed(WWidget *w) const; /*! \brief Progresses to an Ajax-enabled user interface. * * This method is called when the progressive bootstrap method is used, and * support for AJAX has been detected. The default behavior will propagate * the WWidget::enableAjax() method through the widget hierarchy. * * You may want to reimplement this method if you want to make * changes to the user-interface when AJAX is enabled. You should * always call the base implementation. * * \sa WWidget::enableAjax() */ virtual void enableAjax(); /*! \brief Handles a browser unload event. * * The browser unloads the application when the user navigates away or * when he closes the window or tab. * * When reload-is-new-session is set to \c true, then the * default implementation of this method terminates this session by * calling quit(), otherwise the session is scheduled to expire within * seconds (since it may be a refresh). * * You may want to reimplement this if you want to keep the * application running until it times out (as was the behaviour * before %Wt 3.1.6). */ virtual void unload(); /*! \brief Idle timeout handler * * \if cpp * If idle-timeout is set in the configuration, this method is called when * the user seems idle for the number of seconds set in idle-timeout. * \elseif java * If idle timeout is set in the configuration * ({@link Configuration#setIdleTimeout(int)}), this * method is called when the user seems idle for the number of seconds set as the * idle timeout. * \endif * * This feature can be useful in security sensitive applications * to prevent unauthorized users from taking over the session * of a user that has moved away from or left behind * the device from which they are accessing the %Wt application. * * The default implementation logs that a timeout has occurred, * and calls quit(). * * This method can be overridden to specify different timeout behaviour, * e.g. to show a dialog that a user's session has expired, or that * the session is about to expire. * * \if cpp * * Example for an expiration dialog: * * \code * class MyApplication : public Wt::WApplication { * public: * MyApplication(Wt::WEnvironment &env) * : WApplication(env) * { } * * protected: * virtual void idleTimeout() override * { * if (idleTimeoutDialog_) * return; // Prevent multiple dialogs * * idleTimeoutDialog_ = addChild(std::make_unique("Idle timeout")); * idleTimeoutDialog_->contents()->addNew("This session will automatically quit in 1 minute, " * "press 'abort' to continue using the application"); * auto btn = idleTimeoutDialog_->footer()->addNew("abort"); * btn->clicked().connect([this]{ * removeChild(idleTimeoutDialog_.get()); * }); * auto timer = idleTimeoutDialog_->addChild(std::make_unique()); * timer->setInterval(std::chrono::seconds{60}); * timer->setSingleShot(true); * timer->timeout().connect([this]{ * quit(); * }); * timer->start(); * idleTimeoutDialog_->show(); * } * * private: * Wt::Core::observing_ptr idleTimeoutDialog_; * }; * \endcode * * \endif * * \note The events currently counted as user activity are: * - mousedown * - mouseup * - wheel * - keydown * - keyup * - touchstart * - touchend * - pointerdown * - pointerup */ virtual void idleTimeout(); /** * @brief handleJavaScriptError print javaScript errors to log file. * You may want to overwrite it to render error page for example. * * @param errorText the error will usually be in json format. */ virtual void handleJavaScriptError(const std::string& errorText); private: Signal< ::int64_t > requestTooLarge_; struct ScriptLibrary { ScriptLibrary(const std::string& uri, const std::string& symbol); std::string uri, symbol, beforeLoadJS; bool operator< (const ScriptLibrary& other) const; bool operator== (const ScriptLibrary& other) const; }; struct MetaLink { MetaLink(const std::string &href, const std::string &rel, const std::string &media, const std::string &hreflang, const std::string &type, const std::string &sizes, bool disabled); std::string href; std::string rel; std::string media; std::string hreflang; std::string type; std::string sizes; bool disabled; }; #ifndef WT_TARGET_JAVA typedef std::map SignalMap; typedef std::map ResourceMap; #else typedef std::weak_value_map SignalMap; typedef std::weak_value_map ResourceMap; #endif typedef std::map ObjectMap; /* * Basic application stuff */ WebSession *session_; // session owning this application #ifndef WT_CNOR std::weak_ptr weakSession_; // used to sense destruction #endif // WT_CNOR WString title_, closeMessage_; bool titleChanged_, closeMessageChanged_, localeChanged_; std::unique_ptr domRoot_; // main DOM root WContainerWidget *widgetRoot_; // widgets in main DOM root WContainerWidget *timerRoot_; // timers in main DOM root std::unique_ptr domRoot2_; // other virtual root WCssStyleSheet styleSheet_; // internal stylesheet std::unique_ptr localizedStrings_; WLocale locale_; std::string renderedInternalPath_, newInternalPath_; Signal internalPathChanged_, internalPathInvalid_; bool internalPathIsChanged_, internalPathDefaultValid_, internalPathValid_; int serverPush_; bool serverPushChanged_; #ifndef WT_TARGET_JAVA boost::pool *eventSignalPool_; #endif // WT_TARGET_JAVA std::string javaScriptClass_; bool quitted_; WString quittedMessage_; std::unique_ptr onePixelGifR_; bool internalPathsEnabled_; WWidget *exposedOnly_; WLoadingIndicator *loadingIndicator_; std::string htmlClass_, bodyClass_; bool bodyHtmlClassChanged_, enableAjax_; #ifndef WT_TARGET_JAVA bool initialized_; #endif // WT_TARGET_JAVA std::string focusId_; int selectionStart_, selectionEnd_; LayoutDirection layoutDirection_; std::vector scriptLibraries_; int scriptLibrariesAdded_; std::shared_ptr theme_; std::vector styleSheets_; std::vector styleSheetsToRemove_; int styleSheetsAdded_; std::vector metaHeaders_; std::vector metaLinks_; SignalMap exposedSignals_; // signals that may be accessed ResourceMap exposedResources_; // resources that may be accessed ObjectMap encodedObjects_; // objects encoded for internal purposes // like 'virtual pointers' (see D&D) std::set justRemovedSignals_; bool exposeSignals_; // if we are currently exposing signals (see WViewWidget) std::string afterLoadJavaScript_, beforeLoadJavaScript_; int newBeforeLoadJavaScript_; std::string autoJavaScript_; bool autoJavaScriptChanged_; #ifndef WT_DEBUG_JS std::vector javaScriptPreamble_; int newJavaScriptPreamble_; #else std::vector newJavaScriptToLoad_; #endif // WT_DEBUG_JS std::set javaScriptLoaded_; bool customJQuery_; EventSignal<> showLoadingIndicator_, hideLoadingIndicator_; JSignal<> unloaded_; JSignal<> idleTimeout_; WContainerWidget *timerRoot() const { return timerRoot_; } WEnvironment& env(); // short-hand for session_->env() /* * Functions for exposed signals, resources, and objects */ void addExposedSignal(EventSignalBase* signal); void removeExposedSignal(EventSignalBase* signal); EventSignalBase *decodeExposedSignal(const std::string& signalName) const; std::string encodeSignal(const std::string& objectId, const std::string& name) const; SignalMap& exposedSignals() { return exposedSignals_; } std::set& justRemovedSignals() { return justRemovedSignals_; } std::string resourceMapKey(WResource *resource); std::string addExposedResource(WResource *resource); bool removeExposedResource(WResource *resource); WResource *decodeExposedResource(const std::string& resourceMapKey) const; /* * Methods for application state handling */ bool changeInternalPath(const std::string& path); bool changedInternalPath(const std::string& path); /* * Methods for accessing javaScript, which may have erase-on-read * semantics */ void streamAfterLoadJavaScript(WStringStream& out); void streamBeforeLoadJavaScript(WStringStream& out, bool all); void streamJavaScriptPreamble(WStringStream& out, bool all); #ifdef WT_DEBUG_JS void loadJavaScriptFile(WStringStream& out, const char *jsFile); #endif // WT_DEBUG_JS /* * Methods that control exposing of signals */ void setExposeSignals(bool how) { exposeSignals_ = how; } bool exposeSignals() const { return exposeSignals_; } void doUnload(); void doIdleTimeout(); #ifndef WT_TARGET_JAVA int startWaitingAtLock(); void endWaitingAtLock(int id); #endif // WT_TARGET_JAVA std::string focus() const { return focusId_; } int selectionStart() const { return selectionStart_; } int selectionEnd() const { return selectionEnd_; } WLocalizedStrings *localizedStringsPack(); /* * Methods for audio handling */ SoundManager *getSoundManager(); SoundManager *soundManager_; static const char *RESOURCES_URL; #ifdef WT_TARGET_JAVA JSlot showLoadJS; JSlot hideLoadJS; #endif friend class WCssStyleSheet; friend class WebRenderer; friend class WebSession; friend class WebController; friend class EventSignalBase; friend class JavaScriptEvent; friend class UpdateLockImpl; friend class WContainerWidget; friend class WDialog; friend class WFileUpload; friend class WInteractWidget; friend class WLineEdit; friend class WMenu; friend class WResource; friend class WSound; friend class WString; friend class WTextArea; friend class WTimer; friend class WViewWidget; friend class WWidget; friend class WWebWidget; }; #ifndef WT_TARGET_JAVA #ifdef DOXYGEN_ONLY /*! \brief Runs the %Wt application server. * * This function runs the application server, and should be called * only once (e.g. from within your main function). * * The \p createApplication parameter is a std::function * object that should create a new application instance for a new user * visiting the application. It is of type: * std::function, and thus you can pass to it a function * like: * *
 * Wt::WApplication *createApplication(const Wt::WEnvironment& env)
 * {
 *   // ...
 * }
 * 
* * When using the built-in httpd, the implementation listens for POSIX * termination signals (or console CTRL-C) event. You can use the * WServer class for more flexible control on starting and stopping * the server. * * \relates WServer * \sa WApplication */ extern int WRun(int argc, char** argv, ApplicationCreator createApplication = 0); #else // DOXYGEN_ONLY extern int WTCONNECTOR_API WRun(int argc, char** argv, ApplicationCreator createApplication = ApplicationCreator()); #endif // DOXYGEN_ONLY #ifdef DOXYGEN_ONLY /*! \brief Runs the %Wt application server. * * This function runs the application server, and should be called * only once (e.g. from within your main function). * * The \p createApplication parameter is a std::function * object that should create a new application instance for a new user * visiting the application. It is of type: * std::function, and thus you can pass to it a function * like: * *
 * Wt::WApplication *createApplication(const Wt::WEnvironment& env)
 * {
 *   // ...
 * }
 * 
* * When using the built-in httpd, the implementation listens for POSIX * termination signals (or console CTRL-C) event. You can use the * WServer class for more flexible control on starting and stopping * the server. * * This version of WRun() takes a std::string * for the application path, and a vector of arguments (not including * argv[0], the application path) instead of argc and argv, * for better convenience when arguments are not provided via * the command line. * * \relates WServer * \sa WApplication */ extern int WRun(const std::string &applicationPath, const std::vector &args, ApplicationCreator createApplication = 0); #else // DOXYGEN_ONLY extern int WTCONNECTOR_API WRun(const std::string &applicationPath, const std::vector &args, ApplicationCreator createApplication = ApplicationCreator()); #endif // DOXYGEN_ONLY #endif // WT_TARGET_JAVA /*! \def wApp * \brief Global constant for accessing the application instance. * * This is equivalent to WApplication::instance() * * \relates WApplication */ #define wApp Wt::WApplication::instance() } #endif // WAPPLICATION_