[Merge] lp:~osomon/webbrowser-app/contextual-selection into lp:webbrowser-app

Didier Roche didrocks at ubuntu.com
Thu Jun 26 13:40:58 UTC 2014


Review: Needs Fixing

See the inline comment, once that's fixed: +1

Diff comments:

> === modified file '.bzrignore'
> --- .bzrignore	2014-05-30 16:16:56 +0000
> +++ .bzrignore	2014-06-26 12:56:18 +0000
> @@ -30,8 +30,8 @@
>  debian/files
>  debian/tmp/
>  debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin/
> -debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets/
>  debian/qtdeclarative5-ubuntu-web-plugin/
> +debian/qtdeclarative5-ubuntu-web-plugin-assets/
>  debian/webapp-container/
>  debian/webapp-container-autopilot/
>  debian/webbrowser-app/
> 
> === modified file 'debian/control'
> --- debian/control	2014-06-16 08:34:26 +0000
> +++ debian/control	2014-06-26 12:56:18 +0000
> @@ -78,7 +78,6 @@
>           ${shlibs:Depends},
>           libqt5webkit5-qmlwebkitplugin,
>           qtdeclarative5-qtquick2-plugin,
> -         qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets (>= ${source:Version}),
>           qtdeclarative5-ubuntu-ui-toolkit-plugin,
>           qtdeclarative5-ubuntu-web-plugin (= ${binary:Version}),
>           qtdeclarative5-window-plugin,
> @@ -89,16 +88,6 @@
>   (versions 0.1 based on WebKit and 0.2 based on Oxide), in the
>   Ubuntu.Components.Extras.Browser module.
>  
> -Package: qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets
> -Architecture: all
> -Multi-Arch: foreign
> -Depends: ${misc:Depends},
> -Description: Ubuntu web QML plugin assets
> - A standalone QML plugin that contains the UbuntuWebView component
> - (versions 0.1 based on WebKit and 0.2 based on Oxide), in the
> - Ubuntu.Components.Extras.Browser module. This package contains the
> - PNGs used as UI elements by the plugin.
> -
>  Package: qtdeclarative5-ubuntu-web-plugin
>  Architecture: any
>  Multi-Arch: same
> @@ -108,11 +97,22 @@
>           liboxideqt-qmlplugin,
>           qtdeclarative5-qtquick2-plugin,
>           qtdeclarative5-ubuntu-ui-toolkit-plugin,
> +         qtdeclarative5-ubuntu-web-plugin-assets (>= ${source:Version}),
>           qtdeclarative5-window-plugin,
>  Description: Ubuntu web QML plugin
>   A standalone QML plugin that contains the WebView component,
>   in the Ubuntu.Web module.
>  
> +Package: qtdeclarative5-ubuntu-web-plugin-assets
> +Architecture: all
> +Multi-Arch: foreign
> +Depends: ${misc:Depends},
> +Replaces: qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets

There is no need for replaces: as you don't install any common filename with qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets from that package. You can just remove it.

> +Description: Ubuntu web QML plugin assets
> + A standalone QML plugin that contains the WebView component,
> + in the Ubuntu.Web module. This package contains the PNGs used
> + as UI elements by the plugin.
> +
>  Package: webbrowser-app-autopilot
>  Architecture: all
>  Multi-Arch: foreign
> 
> === renamed file 'debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets.install' => 'debian/qtdeclarative5-ubuntu-web-plugin-assets.install'
> --- debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets.install	2013-07-18 14:15:53 +0000
> +++ debian/qtdeclarative5-ubuntu-web-plugin-assets.install	2014-06-26 12:56:18 +0000
> @@ -1,1 +1,1 @@
> -usr/share/qtdeclarative5-ubuntu-ui-extras-browser-plugin/
> +usr/share/qtdeclarative5-ubuntu-web-plugin/
> 
> === modified file 'debian/rules'
> --- debian/rules	2014-03-04 09:32:47 +0000
> +++ debian/rules	2014-06-26 12:56:18 +0000
> @@ -11,7 +11,9 @@
>  	dh $@ --parallel --with translations
>  
>  override_dh_install:
> -	ln -sf /usr/share/qtdeclarative5-ubuntu-ui-extras-browser-plugin/assets \
> +	ln -sf /usr/share/qtdeclarative5-ubuntu-web-plugin/assets \
> +	$(CURDIR)/debian/tmp/usr/lib/*/qt5/qml/Ubuntu/Web
> +	ln -sf /usr/share/qtdeclarative5-ubuntu-web-plugin/assets \
>  	$(CURDIR)/debian/tmp/usr/lib/*/qt5/qml/Ubuntu/Components/Extras/Browser
>  	dh_install --fail-missing
>  
> 
> === modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt'
> --- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt	2014-05-29 17:03:44 +0000
> +++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt	2014-06-26 12:56:18 +0000
> @@ -13,19 +13,14 @@
>  file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
>  install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR})
>  install(FILES ${QML_FILES} DESTINATION ${WEBBROWSER_IMPORTS_DIR})
> -install(DIRECTORY assets
> -        DESTINATION ${CMAKE_INSTALL_DATADIR}/qtdeclarative5-ubuntu-ui-extras-browser-plugin
> -        FILES_MATCHING PATTERN *.png)
>  
>  if(NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
>    # copy qml files and assets over to build dir to be able to import them uninstalled
> -  file(GLOB ASSETS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} assets/*)
> -  set(copied ${QML_FILES} ${ASSETS})
> -  foreach(_file ${copied})
> +  foreach(_file ${QML_FILES})
>      add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_file}
>                         DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_file}
>                         COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_file} ${CMAKE_CURRENT_BINARY_DIR}/${_file})
>    endforeach(_file)
> -  add_custom_target(copy_files_to_build_dir_legacy DEPENDS ${copied})
> +  add_custom_target(copy_files_to_build_dir_legacy DEPENDS ${QML_FILES})
>    add_dependencies(${PLUGIN} copy_files_to_build_dir_legacy)
>  endif()
> 
> === added symlink 'src/Ubuntu/Components/Extras/Browser/Selection.qml'
> === target is u'../../../Web/Selection.qml'
> === added symlink 'src/Ubuntu/Components/Extras/Browser/SelectionHandle.qml'
> === target is u'../../../Web/SelectionHandle.qml'
> === added symlink 'src/Ubuntu/Components/Extras/Browser/assets'
> === target is u'../../../Web/assets/'
> === modified file 'src/Ubuntu/Web/CMakeLists.txt'
> --- src/Ubuntu/Web/CMakeLists.txt	2014-05-29 17:03:44 +0000
> +++ src/Ubuntu/Web/CMakeLists.txt	2014-06-26 12:56:18 +0000
> @@ -13,6 +13,9 @@
>  file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
>  install(TARGETS ${PLUGIN} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR})
>  install(FILES ${QML_FILES} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR})
> +install(DIRECTORY assets
> +        DESTINATION ${CMAKE_INSTALL_DATADIR}/qtdeclarative5-ubuntu-web-plugin
> +        FILES_MATCHING PATTERN *.png)
>  
>  if(NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
>    # copy qml files over to build dir to be able to import them uninstalled
> 
> === renamed file 'src/Ubuntu/Components/Extras/Browser/Selection.qml' => 'src/Ubuntu/Web/Selection.qml'
> --- src/Ubuntu/Components/Extras/Browser/Selection.qml	2013-03-08 10:53:16 +0000
> +++ src/Ubuntu/Web/Selection.qml	2014-06-26 12:56:18 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2013-2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -27,16 +27,20 @@
>      property real __minimumWidth: units.gu(5)
>      property real __minimumHeight: units.gu(5)
>  
> +    readonly property bool resizing: __leftHandle.dragging || __topHandle.dragging || __rightHandle.dragging || __bottomHandle.dragging
> +
>      signal resized()
> +    signal dismissed()
>  
>      MouseArea {
>          anchors.fill: parent
>          // dismiss the selection when tapping anywhere except for the handles
> -        onClicked: __container.visible = false
> +        onClicked: __container.dismissed()
>      }
>  
>      Item {
>          id: __rect
> +        objectName: "rectangle"
>      }
>  
>      Rectangle {
> @@ -91,6 +95,7 @@
>  
>      SelectionHandle {
>          id: __leftHandle
> +        objectName: "leftHandle"
>          axis: Drag.XAxis
>          x: __rect.x - width / 2
>          y: (__topHandle.y + __bottomHandle.y) / 2
> @@ -107,6 +112,7 @@
>  
>      SelectionHandle {
>          id: __topHandle
> +        objectName: "topHandle"
>          axis: Drag.YAxis
>          x: (__leftHandle.x + __rightHandle.x) / 2
>          y: __rect.y - height / 2
> @@ -123,6 +129,7 @@
>  
>      SelectionHandle {
>          id: __rightHandle
> +        objectName: "rightHandle"
>          axis: Drag.XAxis
>          x: __rect.x + __rect.width - width / 2
>          y: (__topHandle.y + __bottomHandle.y) / 2
> @@ -138,6 +145,7 @@
>  
>      SelectionHandle {
>          id: __bottomHandle
> +        objectName: "bottomHandle"
>          axis: Drag.YAxis
>          x: (__leftHandle.x + __rightHandle.x) / 2
>          y: __rect.y + __rect.height - height / 2
> 
> === renamed file 'src/Ubuntu/Components/Extras/Browser/SelectionHandle.qml' => 'src/Ubuntu/Web/SelectionHandle.qml'
> --- src/Ubuntu/Components/Extras/Browser/SelectionHandle.qml	2013-03-08 10:53:16 +0000
> +++ src/Ubuntu/Web/SelectionHandle.qml	2014-06-26 12:56:18 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2013-2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -23,8 +23,6 @@
>      property int axis
>      property real minimum
>      property real maximum
> -    // Known issue: when dragging outside the window, the drag is canceled,
> -    // but dragging remains true. See QTBUG-29146.
>      property bool dragging: __mousearea.drag.active
>  
>      width: units.gu(3)
> 
> === modified file 'src/Ubuntu/Web/UbuntuWebView02.qml'
> --- src/Ubuntu/Web/UbuntuWebView02.qml	2014-06-11 09:31:38 +0000
> +++ src/Ubuntu/Web/UbuntuWebView02.qml	2014-06-26 12:56:18 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2013-2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -62,29 +62,36 @@
>              msgId: "contextmenu"
>              contexts: ["oxide://selection/"]
>              callback: function(msg, frame) {
> -                if (('img' in msg.args) || ('href' in msg.args)) {
> -                    if (internal.currentContextualMenu != null) {
> -                        PopupUtils.close(internal.currentContextualMenu)
> -                    }
> -                    contextualData.clear()
> -                    if ('img' in msg.args) {
> -                        contextualData.img = msg.args.img
> -                    }
> -                    if ('href' in msg.args) {
> -                        contextualData.href = msg.args.href
> -                        contextualData.title = msg.args.title
> -                    }
> -                    if (contextualActions != null) {
> -                        for (var i = 0; i < contextualActions.actions.length; ++i) {
> -                            if (contextualActions.actions[i].enabled) {
> -                                contextualRectangle.position(msg.args)
> -                                internal.currentContextualMenu = PopupUtils.open(contextualPopover, contextualRectangle)
> -                                break
> -                            }
> -                        }
> -                    }
> -                } else if (internal.currentContextualMenu != null) {
> -                    PopupUtils.close(internal.currentContextualMenu)
> +                internal.dismissCurrentContextualMenu()
> +                internal.dismissCurrentSelection()
> +                internal.fillContextualData(msg.args)
> +                if (contextualActions != null) {
> +                    for (var i = 0; i < contextualActions.actions.length; ++i) {
> +                        if (contextualActions.actions[i].enabled) {
> +                            contextualRectangle.position(msg.args)
> +                            internal.currentContextualMenu = PopupUtils.open(contextualPopover, contextualRectangle)
> +                            break
> +                        }
> +                    }
> +                }
> +            }
> +        },
> +        Oxide.ScriptMessageHandler {
> +            msgId: "selection"
> +            contexts: ["oxide://selection/"]
> +            callback: function(msg, frame) {
> +                internal.dismissCurrentSelection()
> +                internal.dismissCurrentContextualMenu()
> +                if (selectionActions != null) {
> +                    for (var i = 0; i < selectionActions.actions.length; ++i) {
> +                        if (selectionActions.actions[i].enabled) {
> +                            var mimedata = internal.buildMimedata(msg.args)
> +                            var bounds = internal.computeBounds(msg.args)
> +                            internal.currentSelection = selection.createObject(_webview, {mimedata: mimedata, bounds: bounds})
> +                            internal.currentSelection.showActions()
> +                            break
> +                        }
> +                    }
>                  }
>              }
>          },
> @@ -92,9 +99,8 @@
>              msgId: "scroll"
>              contexts: ["oxide://selection/"]
>              callback: function(msg, frame) {
> -                if (internal.currentContextualMenu != null) {
> -                    PopupUtils.close(internal.currentContextualMenu)
> -                }
> +                internal.dismissCurrentContextualMenu()
> +                internal.dismissCurrentSelection()
>              }
>          }
>      ]
> @@ -140,10 +146,127 @@
>          }
>      }
>  
> +    property ActionList selectionActions
> +    onSelectionActionsChanged: {
> +        for (var i in selectionActions.actions) {
> +            selectionActions.actions[i].onTriggered.connect(function () {
> +                internal.dismissCurrentSelection()
> +            })
> +        }
> +    }
> +    Component {
> +        id: selection
> +        Selection {
> +            anchors.fill: parent
> +            property var mimedata: null
> +            property rect bounds
> +            onBoundsChanged: {
> +                rect.x = bounds.x
> +                rect.y = bounds.y
> +                rect.width = bounds.width
> +                rect.height = bounds.height
> +            }
> +            property Item actions: null
> +            Component {
> +                id: selectionPopover
> +                ActionSelectionPopover {
> +                    objectName: "selectionActions"
> +                    autoClose: false
> +                    actions: selectionActions
> +                }
> +            }
> +            function showActions() {
> +                if (actions != null) {
> +                    actions.destroy()
> +                }
> +                actions = PopupUtils.open(selectionPopover, rect)
> +            }
> +            onResizingChanged: {
> +                if (resizing) {
> +                    if (actions != null) {
> +                        actions.destroy()
> +                    }
> +                }
> +            }
> +            onResized: {
> +                var args = {x: rect.x, y: rect.y, width: rect.width, height: rect.height}
> +                var msg = _webview.rootFrame.sendMessage("oxide://selection/", "adjustselection", args)
> +                msg.onreply = function(response) {
> +                    internal.currentSelection.mimedata = internal.buildMimedata(response)
> +                    // Ensure that the bounds are updated
> +                    internal.currentSelection.bounds = Qt.rect(0, 0, 0, 0)
> +                    internal.currentSelection.bounds = internal.computeBounds(response)
> +                    internal.currentSelection.showActions()
> +                }
> +                msg.onerror = function(error) {
> +                    internal.dismissCurrentSelection()
> +                }
> +            }
> +            onDismissed: internal.dismissCurrentSelection()
> +        }
> +    }
> +    function copy() {
> +        if (internal.currentSelection != null) {
> +            Clipboard.push(internal.currentSelection.mimedata)
> +        } else {
> +            console.warn("No current selection")
> +        }
> +    }
> +
>      QtObject {
>          id: internal
>          property int lastLoadRequestStatus: -1
>          property Item currentContextualMenu: null
> +        property Item currentSelection: null
> +
> +        function fillContextualData(data) {
> +            contextualData.clear()
> +            if ('img' in data) {
> +                contextualData.img = data.img
> +            }
> +            if ('href' in data) {
> +                contextualData.href = data.href
> +                contextualData.title = data.title
> +            }
> +        }
> +
> +        function buildMimedata(data) {
> +            var mimedata = Clipboard.newData()
> +            if ('html' in data) {
> +                mimedata.html = data.html
> +            }
> +            // FIXME: push the text and image data in the order
> +            // they appear in the selected block.
> +            if ('text' in data) {
> +                mimedata.text = data.text
> +            }
> +            if ('images' in data) {
> +                // TODO: download and cache the images locally
> +                // (grab them from the webview’s cache, if possible),
> +                // and forward local URLs.
> +                mimedata.urls = data.images
> +            }
> +            return mimedata
> +        }
> +
> +        function computeBounds(data) {
> +            return Qt.rect(data.left * data.scaleX, data.top * data.scaleY,
> +                           data.width * data.scaleX, data.height * data.scaleY)
> +        }
> +
> +        function dismissCurrentContextualMenu() {
> +            if (currentContextualMenu != null) {
> +                PopupUtils.close(currentContextualMenu)
> +            }
> +        }
> +
> +        function dismissCurrentSelection() {
> +            if (currentSelection != null) {
> +                // For some reason a 0 delay fails to destroy the selection
> +                // when it was requested upon a screen orientation change…
> +                currentSelection.destroy(1)
> +            }
> +        }
>      }
>  
>      readonly property bool lastLoadSucceeded: internal.lastLoadRequestStatus === Oxide.LoadEvent.TypeSucceeded
> @@ -157,9 +280,8 @@
>  
>      readonly property int screenOrientation: Screen.orientation
>      onScreenOrientationChanged: {
> -        if (internal.currentContextualMenu != null) {
> -            PopupUtils.close(internal.currentContextualMenu)
> -        }
> +        internal.dismissCurrentContextualMenu()
> +        internal.dismissCurrentSelection()
>      }
>  
>      onFullscreenRequested: _webview.fullscreen = fullscreen
> 
> === renamed directory 'src/Ubuntu/Components/Extras/Browser/assets' => 'src/Ubuntu/Web/assets'
> === modified file 'src/Ubuntu/Web/selection02.js'
> --- src/Ubuntu/Web/selection02.js	2014-05-29 16:45:21 +0000
> +++ src/Ubuntu/Web/selection02.js	2014-06-26 12:56:18 +0000
> @@ -16,6 +16,12 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +function elementContainedInBox(element, box) {
> +    var rect = element.getBoundingClientRect();
> +    return ((box.left <= rect.left) && (box.right >= rect.right) &&
> +            (box.top <= rect.top) && (box.bottom >= rect.bottom));
> +}
> +
>  function getImgFullUri(uri) {
>      if ((uri.slice(0, 7) === 'http://') ||
>          (uri.slice(0, 8) === 'https://') ||
> @@ -98,15 +104,48 @@
>      return data;
>  }
>  
> +function adjustSelection(selection) {
> +    // FIXME: allow selecting two consecutive blocks, instead of
> +    // interpolating to the containing block.
> +    var centerX = (selection.left + selection.right) / 2;
> +    var centerY = (selection.top + selection.bottom) / 2;
> +    var element = document.elementFromPoint(centerX, centerY);
> +    var parent = element;
> +    while (elementContainedInBox(parent, selection)) {
> +        parent = parent.parentNode;
> +    }
> +    element = parent;
> +    return getSelectedData(element);
> +}
> +
>  document.documentElement.addEventListener('contextmenu', function(event) {
>      var element = document.elementFromPoint(event.clientX, event.clientY);
>      var data = getSelectedData(element);
>      var w = document.defaultView;
>      data['scaleX'] = w.outerWidth / w.innerWidth * w.devicePixelRatio;
>      data['scaleY'] = w.outerHeight / w.innerHeight * w.devicePixelRatio;
> -    oxide.sendMessage('contextmenu', data);
> +    if (('img' in data) || ('href' in data)) {
> +        oxide.sendMessage('contextmenu', data);
> +    } else {
> +        oxide.sendMessage('selection', data);
> +    }
>  });
>  
>  document.defaultView.addEventListener('scroll', function(event) {
>      oxide.sendMessage('scroll', {});
>  });
> +
> +oxide.addMessageHandler("adjustselection", function (msg) {
> +    var w = document.defaultView;
> +    var scaleX = w.outerWidth / w.innerWidth * w.devicePixelRatio;
> +    var scaleY = w.outerHeight / w.innerHeight * w.devicePixelRatio;
> +    var selection = new Object;
> +    selection.left = msg.args.x / scaleX;
> +    selection.right = selection.left + msg.args.width / scaleX;
> +    selection.top = msg.args.y / scaleY;
> +    selection.bottom = selection.top + msg.args.height / scaleY;
> +    var adjusted = adjustSelection(selection);
> +    adjusted['scaleX'] = scaleX;
> +    adjusted['scaleY'] = scaleY;
> +    msg.reply(adjusted);
> +});
> 
> === modified file 'src/app/WebViewImpl.qml'
> --- src/app/WebViewImpl.qml	2014-06-18 05:55:37 +0000
> +++ src/app/WebViewImpl.qml	2014-06-26 12:56:18 +0000
> @@ -20,7 +20,7 @@
>  import Ubuntu.Components 0.1
>  import Ubuntu.Components.Popups 0.1
>  import Ubuntu.Web 0.2
> -//import "actions" as Actions
> +import "actions" as Actions
>  
>  WebView {
>      id: webview
> @@ -42,11 +42,11 @@
>          source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml"
>      }
>  
> -    /*selectionActions: ActionList {
> +    selectionActions: ActionList {
>          Actions.Copy {
> -            onTriggered: selection.copy()
> +            onTriggered: copy()
>          }
> -    }*/
> +    }
>  
>      onGeolocationPermissionRequested: {
>          if (webview.toolbar) {
> 
> === modified file 'tests/autopilot/webbrowser_app/emulators/browser.py'
> --- tests/autopilot/webbrowser_app/emulators/browser.py	2014-06-18 13:57:07 +0000
> +++ tests/autopilot/webbrowser_app/emulators/browser.py	2014-06-26 12:56:18 +0000
> @@ -21,6 +21,15 @@
>      pass
>  
>  
> +class Selection(uitk.UbuntuUIToolkitEmulatorBase):
> +
> +    def get_rectangle(self):
> +        return self.select_single("QQuickItem", objectName="rectangle")
> +
> +    def get_handle(self, name):
> +        return self.select_single("SelectionHandle", objectName=name)
> +
> +
>  class Browser(uitk.MainView):
>  
>      """
> @@ -106,3 +115,10 @@
>  
>      def get_geolocation_dialog(self):
>          return self.wait_select_single("GeolocationPermissionRequest")
> +
> +    def get_selection(self):
> +        return self.wait_select_single(Selection)
> +
> +    def get_selection_actions(self):
> +        return self.wait_select_single("ActionSelectionPopover",
> +                                       objectName="selectionActions")
> 
> === modified file 'tests/autopilot/webbrowser_app/tests/http_server.py'
> --- tests/autopilot/webbrowser_app/tests/http_server.py	2014-06-18 13:57:07 +0000
> +++ tests/autopilot/webbrowser_app/tests/http_server.py	2014-06-26 12:56:18 +0000
> @@ -121,6 +121,12 @@
>              html += 'navigator.geolocation.getCurrentPosition('
>              html += 'function r(p) {});</script></body></html>'
>              self.send_html(html)
> +        elif self.path == "/selection":
> +            self.send_response(200)
> +            html = '<html><body style="margin: 10%">'
> +            html += '<div style="position: absolute; width: 50%; height: 50%; '
> +            html += 'top: 25%; left: 25%"></div></body></html>'
> +            self.send_html(html)
>          else:
>              self.send_error(404)
>  
> 
> === added file 'tests/autopilot/webbrowser_app/tests/test_selection.py'
> --- tests/autopilot/webbrowser_app/tests/test_selection.py	1970-01-01 00:00:00 +0000
> +++ tests/autopilot/webbrowser_app/tests/test_selection.py	2014-06-26 12:56:18 +0000
> @@ -0,0 +1,91 @@
> +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
> +#
> +# Copyright 2014 Canonical
> +#
> +# This program is free software: you can redistribute it and/or modify it
> +# under the terms of the GNU General Public License version 3, as published
> +# by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +import time
> +from autopilot.platform import model
> +from autopilot.matchers import Eventually
> +from testtools.matchers import Equals, GreaterThan, LessThan
> +
> +from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
> +
> +
> +class TestSelection(StartOpenRemotePageTestCaseBase):
> +
> +    def setUp(self):
> +        super(TestSelection, self).setUp()
> +        url = self.base_url + "/selection"
> +        self.go_to_url(url)
> +        self.assert_page_eventually_loaded(url)
> +        webview = self.main_window.get_current_webview()
> +        self.pointing_device.move_to_object(webview)
> +        if model() == 'Desktop':
> +            self.pointing_device.click(button=3)
> +        else:
> +            self.pointing_device.press()
> +            time.sleep(1)
> +            self.pointing_device.release()
> +        self.selection = self.main_window.get_selection()
> +        self.rectangle = self.selection.get_rectangle()
> +        self.assertThat(self.rectangle.width, LessThan(webview.width))
> +        self.assertThat(self.rectangle.height, LessThan(webview.height))
> +        self.actions = self.main_window.get_selection_actions()
> +        self.assertThat(len(self.actions.select_many("Empty")), Equals(1))
> +
> +    def assert_selection_eventually_dismissed(self):
> +        self.actions.wait_until_destroyed()
> +        self.selection.wait_until_destroyed()
> +
> +    def test_copy_selection(self):
> +        copy_action = self.actions.select_single("Empty")
> +        self.pointing_device.click_object(copy_action)
> +        self.assert_selection_eventually_dismissed()
> +
> +    def test_cancel_selection(self):
> +        webview = self.main_window.get_current_webview()
> +        x = int((webview.globalRect.x + self.rectangle.globalRect.x) / 2)
> +        y = int(webview.globalRect.y + webview.globalRect.height / 2)
> +        self.pointing_device.move(x, y)
> +        self.pointing_device.click()
> +        self.assert_selection_eventually_dismissed()
> +
> +    def test_resize_selection(self):
> +        webview = self.main_window.get_current_webview()
> +        rect = self.rectangle.globalRect
> +
> +        # Grow selection to the right
> +        handle = self.selection.get_handle("rightHandle")
> +        x0 = handle.globalRect.x + int(handle.globalRect.width / 2)
> +        y0 = handle.globalRect.y + int(handle.globalRect.height / 2)
> +        x1 = int((x0 + webview.globalRect.x + webview.globalRect.width) / 2)
> +        y1 = y0
> +        self.pointing_device.drag(x0, y0, x1, y1)
> +        self.assertThat(self.rectangle.width,
> +                        Eventually(GreaterThan(rect.width)))
> +        self.assertThat(self.rectangle.height,
> +                        Eventually(GreaterThan(rect.height)))
> +        self.actions.wait_until_destroyed()
> +        self.actions = self.main_window.get_selection_actions()
> +
> +        # Shrink selection from the bottom
> +        handle = self.selection.get_handle("bottomHandle")
> +        x0 = handle.globalRect.x + int(handle.globalRect.width / 2)
> +        y0 = handle.globalRect.y + int(handle.globalRect.height / 2)
> +        x1 = x0
> +        y1 = webview.globalRect.y + int(webview.globalRect.height * 0.6)
> +        self.pointing_device.drag(x0, y0, x1, y1)
> +        self.assertThat(self.rectangle.globalRect, Eventually(Equals(rect)))
> +        self.actions.wait_until_destroyed()
> +        self.actions = self.main_window.get_selection_actions()
> 


-- 
https://code.launchpad.net/~osomon/webbrowser-app/contextual-selection/+merge/223760
Your team Ubuntu Phablet Team is subscribed to branch lp:webbrowser-app.



More information about the Ubuntu-reviews mailing list