1/*
2 * Copyright (C) 2015 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitEditorState.h"
22
23#include "EditorState.h"
24#include "WebKitEditorStatePrivate.h"
25#include "WebPageProxy.h"
26#include <glib/gi18n-lib.h>
27#include <wtf/glib/WTFGType.h>
28
29using namespace WebKit;
30
31/**
32 * SECTION: WebKitEditorState
33 * @Short_description: Web editor state
34 * @Title: WebKitEditorState
35 * @See_also: #WebKitWebView
36 *
37 * WebKitEditorState represents the state of a #WebKitWebView editor.
38 * Use webkit_web_view_get_editor_state() to get the WebKitEditorState
39 * of a #WebKitWebView.
40 *
41 * Since: 2.10
42 */
43
44enum {
45 PROP_0,
46
47 PROP_TYPING_ATTRIBUTES
48};
49
50struct _WebKitEditorStatePrivate {
51 WebPageProxy* page;
52 unsigned typingAttributes;
53 unsigned isCutAvailable : 1;
54 unsigned isCopyAvailable : 1;
55 unsigned isPasteAvailable : 1;
56 unsigned isUndoAvailable : 1;
57 unsigned isRedoAvailable : 1;
58};
59
60WEBKIT_DEFINE_TYPE(WebKitEditorState, webkit_editor_state, G_TYPE_OBJECT)
61
62static void webkitEditorStateGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
63{
64 WebKitEditorState* editorState = WEBKIT_EDITOR_STATE(object);
65
66 switch (propId) {
67 case PROP_TYPING_ATTRIBUTES:
68 g_value_set_uint(value, webkit_editor_state_get_typing_attributes(editorState));
69 break;
70 default:
71 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
72 }
73}
74
75static void webkit_editor_state_class_init(WebKitEditorStateClass* editorStateClass)
76{
77 GObjectClass* objectClass = G_OBJECT_CLASS(editorStateClass);
78 objectClass->get_property = webkitEditorStateGetProperty;
79
80 /**
81 * WebKitEditorState:typing-attributes:
82 *
83 * Bitmask of #WebKitEditorTypingAttributes flags.
84 * See webkit_editor_state_get_typing_attributes() for more information.
85 *
86 * Since: 2.10
87 */
88 g_object_class_install_property(
89 objectClass,
90 PROP_TYPING_ATTRIBUTES,
91 g_param_spec_uint(
92 "typing-attributes",
93 _("Typing Attributes"),
94 _("Flags with the typing attributes"),
95 0, G_MAXUINT, 0,
96 WEBKIT_PARAM_READABLE));
97}
98
99static void webkitEditorStateSetTypingAttributes(WebKitEditorState* editorState, unsigned typingAttributes)
100{
101 if (typingAttributes == editorState->priv->typingAttributes)
102 return;
103
104 editorState->priv->typingAttributes = typingAttributes;
105 g_object_notify(G_OBJECT(editorState), "typing-attributes");
106}
107
108WebKitEditorState* webkitEditorStateCreate(WebPageProxy& page)
109{
110 WebKitEditorState* editorState = WEBKIT_EDITOR_STATE(g_object_new(WEBKIT_TYPE_EDITOR_STATE, nullptr));
111 editorState->priv->page = &page;
112 webkitEditorStateChanged(editorState, page.editorState());
113 return editorState;
114}
115
116void webkitEditorStateChanged(WebKitEditorState* editorState, const EditorState& newState)
117{
118 if (newState.isMissingPostLayoutData)
119 return;
120
121 unsigned typingAttributes = WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE;
122 const auto& postLayoutData = newState.postLayoutData();
123 if (postLayoutData.typingAttributes & AttributeBold)
124 typingAttributes |= WEBKIT_EDITOR_TYPING_ATTRIBUTE_BOLD;
125 if (postLayoutData.typingAttributes & AttributeItalics)
126 typingAttributes |= WEBKIT_EDITOR_TYPING_ATTRIBUTE_ITALIC;
127 if (postLayoutData.typingAttributes & AttributeUnderline)
128 typingAttributes |= WEBKIT_EDITOR_TYPING_ATTRIBUTE_UNDERLINE;
129 if (postLayoutData.typingAttributes & AttributeStrikeThrough)
130 typingAttributes |= WEBKIT_EDITOR_TYPING_ATTRIBUTE_STRIKETHROUGH;
131
132 webkitEditorStateSetTypingAttributes(editorState, typingAttributes);
133
134 editorState->priv->isCutAvailable = postLayoutData.canCut;
135 editorState->priv->isCopyAvailable = postLayoutData.canCopy;
136 editorState->priv->isPasteAvailable = postLayoutData.canPaste;
137
138 editorState->priv->isUndoAvailable = editorState->priv->page->canUndo();
139 editorState->priv->isRedoAvailable = editorState->priv->page->canRedo();
140}
141
142/**
143 * webkit_editor_state_get_typing_attributes:
144 * @editor_state: a #WebKitEditorState
145 *
146 * Gets the typing attributes at the current cursor position.
147 * If there is a selection, this returns the typing attributes
148 * of the selected text. Note that in case of a selection,
149 * typing attributes are considered active only when they are
150 * present throughout the selection.
151 *
152 * Returns: a bitmask of #WebKitEditorTypingAttributes flags
153 *
154 * Since: 2.10
155 */
156guint webkit_editor_state_get_typing_attributes(WebKitEditorState* editorState)
157{
158 g_return_val_if_fail(WEBKIT_IS_EDITOR_STATE(editorState), WEBKIT_EDITOR_TYPING_ATTRIBUTE_NONE);
159
160 return editorState->priv->typingAttributes;
161}
162
163/**
164 * webkit_editor_state_is_cut_available:
165 * @editor_state: a #WebKitEditorState
166 *
167 * Gets whether a cut command can be issued.
168 *
169 * Returns: %TRUE if cut is currently available
170 *
171 * Since: 2.20
172 */
173gboolean webkit_editor_state_is_cut_available(WebKitEditorState* editorState)
174{
175 g_return_val_if_fail(WEBKIT_IS_EDITOR_STATE(editorState), FALSE);
176
177 return editorState->priv->isCutAvailable;
178}
179
180/**
181 * webkit_editor_state_is_copy_available:
182 * @editor_state: a #WebKitEditorState
183 *
184 * Gets whether a copy command can be issued.
185 *
186 * Returns: %TRUE if copy is currently available
187 *
188 * Since: 2.20
189 */
190gboolean webkit_editor_state_is_copy_available(WebKitEditorState* editorState)
191{
192 g_return_val_if_fail(WEBKIT_IS_EDITOR_STATE(editorState), FALSE);
193
194 return editorState->priv->isCopyAvailable;
195}
196
197/**
198 * webkit_editor_state_is_paste_available:
199 * @editor_state: a #WebKitEditorState
200 *
201 * Gets whether a paste command can be issued.
202 *
203 * Returns: %TRUE if paste is currently available
204 *
205 * Since: 2.20
206 */
207gboolean webkit_editor_state_is_paste_available(WebKitEditorState* editorState)
208{
209 g_return_val_if_fail(WEBKIT_IS_EDITOR_STATE(editorState), FALSE);
210
211 return editorState->priv->isPasteAvailable;
212}
213
214/**
215 * webkit_editor_state_is_undo_available:
216 * @editor_state: a #WebKitEditorState
217 *
218 * Gets whether an undo command can be issued.
219 *
220 * Returns: %TRUE if undo is currently available
221 *
222 * Since: 2.20
223 */
224gboolean webkit_editor_state_is_undo_available(WebKitEditorState* editorState)
225{
226 g_return_val_if_fail(WEBKIT_IS_EDITOR_STATE(editorState), FALSE);
227
228 return editorState->priv->isUndoAvailable;
229}
230
231/**
232 * webkit_editor_state_is_redo_available:
233 * @editor_state: a #WebKitEditorState
234 *
235 * Gets whether a redo command can be issued.
236 *
237 * Returns: %TRUE if redo is currently available
238 *
239 * Since: 2.20
240 */
241gboolean webkit_editor_state_is_redo_available(WebKitEditorState* editorState)
242{
243 g_return_val_if_fail(WEBKIT_IS_EDITOR_STATE(editorState), FALSE);
244
245 return editorState->priv->isRedoAvailable;
246}
247