[PATCH] Init: Added new file FTPDialog.py

Javier Fernandez (via Code Review) gerrit at gerrit.libreoffice.org
Mon Mar 25 03:46:19 PDT 2013


Hi,

I have submitted a patch for review:

    https://gerrit.libreoffice.org/2998

To pull it, you can do:

    git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/98/2998/1

Init: Added new file FTPDialog.py

Change-Id: Ia5ac3202e602fa5154510c7249847713cc76692e
---
A wizards/com/sun/star/wizards/web/FTPDialog.py
1 file changed, 472 insertions(+), 0 deletions(-)



diff --git a/wizards/com/sun/star/wizards/web/FTPDialog.py b/wizards/com/sun/star/wizards/web/FTPDialog.py
new file mode 100644
index 0000000..6cd34ae
--- /dev/null
+++ b/wizards/com/sun/star/wizards/web/FTPDialog.py
@@ -0,0 +1,472 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+import traceback
+import uno
+
+from .WWHID import *
+from .FTPDialogResources import FTPDialogResources
+from ..ui.UnoDialog2 import UnoDialog2
+from ..ui.UIConsts import UIConsts
+from ..ui.event.DataAware import DataAware
+from ..ui.event.UnoDataAware import UnoDataAware
+from ..common.PropertyNames import PropertyNames
+from ..common.SystemDialog import SystemDialog
+from ..common.FileAccess import FileAccess
+from ..common.HelpIds import HelpIds
+from ..common.UCB import UCB
+from .data.CGPublish import CGPublish
+from .data.CGSettings import CGSettings
+
+#from com.sun.star.ucb import AuthenticationRequest
+#from com.sun.star.ucb import InteractiveAugmentedIOException
+#from com.sun.star.ucb import InteractiveNetworkConnectException
+#from com.sun.star.ucb import InteractiveNetworkResolveNameException
+#from com.sun.star.ucb import OpenCommandArgument2
+#from com.sun.star.ucb import OpenMode
+
+PushButtonType_OK_value = uno.getConstantByName( "com.sun.star.awt.PushButtonType.OK" )
+PushButtonType_CANCEL_value = uno.getConstantByName( "com.sun.star.awt.PushButtonType.CANCEL" )
+PushButtonType_HELP_value = uno.getConstantByName( "com.sun.star.awt.PushButtonType.HELP" )
+
+
+# This is the FTP Dialog. <br/>
+# The Dialog enables the user:
+# (*) entering FTP server and user information.
+# (*) testing the connection.
+# (*) choosing a directory on the server.
+# If a connection was established successfully, the user may
+# press OK, which will change
+# the CGPublish object propertiers according the user's input.
+# If no connection was established. the OK and Choose-Dir button are disabled.
+# See the method "disconnect()" which disables them.
+#
+# I use here the DataAware concept to automatically update
+# the members ip, username, and password (via the methods setXXX(...))
+# for details see the ui.events.DataAware classes. <br/>
+class FTPDialog(UnoDialog2, UIConsts):
+
+    # A Constant used for the setLabel(int) method to change the
+    # status-display. "unknown" is the status when the user first
+    # opens the dialog, or changes the servername/username/password.
+    STATUS_UNKONWN = 0
+    # A Constant used for the setLabel(int) method to change the
+    # status-display. (connection established)
+    STATUS_OK = 1
+    # A Constant used for the setLabel(int) method to change the
+    # status-display.
+    STATUS_USER_PWD_WRONG = 2
+    # A Constant used for the setLabel(int) method to change the
+    # status-display.
+    STATUS_SERVER_NOT_FOUND = 3
+    # A Constant used for the setLabel(int) method to change the
+    # status-display.
+    STATUS_NO_RIGHTS = 4
+    # A Constant used for the setLabel(int) method to change the
+    # status-display.
+    STATUS_HOST_UNREACHABLE = 5
+    # A Constant used for the setLabel(int) method to change the
+    # status-display.
+    STATUS_CONNECTING = 6
+    # The icon url for error
+    ICON_ERROR = "ftperror.gif"
+    # The icon url for ok (connection ok)
+    ICON_OK = "ftpconnected.gif"
+    # The icon url for unknown - this is the status when
+    # the user first opens the dialog
+    ICON_UNKNOWN = "ftpunknown.gif"
+    # The icon url for an icon representing the "connecting" state.
+    ICON_CONNECTING = "ftpconnecting.gif"    # GUI Components as Class members.
+    # Fixed Line
+    ln1 = None
+    lblFTPAddress = None
+    txtHost = None
+    lblUsername = None
+    txtUsername = None
+    lblPassword = None
+    txtPassword = None
+    # Fixed Line
+    ln2 = None
+    btnTestConnection = None
+    imgStatus = None
+    lblStatus = None
+    # Fixed Line
+    ln3 = None
+    txtDir = None
+    btnDir = None
+    btnOK = None
+    btnCancel = None
+    btnHelp = None
+    # Font Descriptors as Class members.
+
+    # Resources Object
+    resources = None
+    dataAware = []
+    username = ""
+    password = ""
+
+    #The ftp host name
+    host = ""
+    #The ftp directory.
+    folder = ""
+    #the ftp publish object which contains the
+    #data for this dialog.
+    publish = None
+    ucb = None
+    #used for the status images url.
+    imagesDirectory = ""
+
+    # constructor.
+    # constructs the UI.
+    # @param xmsf
+    # @param p the publishert object that contains the data
+    # for this dialog
+    # @throws Exception
+    def __init__(self, xmsf, p):
+        super(FTPDialog, self).__init__(xmsf)
+        self.publish = p
+
+        #templateDir = p.root.soTemplateDir
+        templateDir = ""
+        self.imagesDirectory = FileAccess.connectURLs(templateDir, "../wizard/bitmap/")
+
+        # Load Resources
+        self.resources = FTPDialogResources(xmsf)
+        self.ucb = UCB(xmsf)
+
+        # set dialog properties...
+        uno.invoke(self.xDialogModel, "setPropertyValues",
+                (("Closeable",
+                 PropertyNames.PROPERTY_HEIGHT,
+                 PropertyNames.PROPERTY_HELPURL, "Moveable",
+                 PropertyNames.PROPERTY_NAME,
+                 PropertyNames.PROPERTY_POSITION_X,
+                 PropertyNames.PROPERTY_POSITION_Y,
+                 "Title",
+                 PropertyNames.PROPERTY_WIDTH),
+                (True,
+                 160,
+                 HelpIds.getHelpIdString(HID_FTP),
+                 True,
+                 "FTPDialog",
+                 167,
+                 82,
+                 self.resources.resFTPDialog_title,
+                 222)))
+
+        # add controls to dialog
+        self.build()
+        #make the hostname, username and password textfield data-aware.
+        self.configure()
+        #make sure we display a disconnected status.
+        self.disconnect()
+
+
+    # Add controls to dialog.
+    def build(self):
+        PROPNAMES_LABEL = (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_LABEL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, PropertyNames.PROPERTY_TABINDEX, PropertyNames.PROPERTY_WIDTH)
+        PROPNAMES_BUTTON = (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL, PropertyNames.PROPERTY_LABEL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, PropertyNames.PROPERTY_TABINDEX, PropertyNames.PROPERTY_WIDTH)
+        PROPNAMES_BUTTON2 = (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL, PropertyNames.PROPERTY_LABEL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, "PushButtonType", PropertyNames.PROPERTY_TABINDEX, PropertyNames.PROPERTY_WIDTH)
+
+        ln1 = self.insertFixedLine("ln1",
+                PROPNAMES_LABEL,
+                (8, self.resources.resln1_value, "ln1", 6, 6, 0, 210))
+        lblFTPAddress = self.insertLabel("lblFTPAddress",
+                PROPNAMES_LABEL,
+                (8, self.resources.reslblFTPAddress_value, "lblFTPAddress", 12, 20, 1, 95))
+        self.txtHost = self.insertTextField("txtHost", "disconnect",
+                (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, PropertyNames.PROPERTY_TABINDEX, PropertyNames.PROPERTY_WIDTH),
+                (12, HelpIds.getHelpIdString(HID_FTP_SERVER), "txtIP", 110, 18, 2, 106), self)
+        self.lblUsername = self.insertLabel("lblUsername",
+                PROPNAMES_LABEL,
+                (8, self.resources.reslblUsername_value, "lblUsername", 12, 36, 3, 85))
+        self.txtUsername = self.insertTextField("txtUsername", "disconnect",
+                (PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, PropertyNames.PROPERTY_TABINDEX, PropertyNames.PROPERTY_WIDTH),
+                (12, HelpIds.getHelpIdString(HID_FTP_USERNAME), "txtUsername", 110, 34, 4, 106), self)
+        self.lblPassword = self.insertLabel("lblPassword",
+                PROPNAMES_LABEL,
+                (8, self.resources.reslblPassword_value, "lblPassword", 12, 52, 5, 85))
+        self.txtPassword = self.insertTextField("txtPassword", "disconnect",
+                ("EchoChar", PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, PropertyNames.PROPERTY_TABINDEX, PropertyNames.PROPERTY_WIDTH),
+                (42, 12, HelpIds.getHelpIdString(HID_FTP_PASS), "txtPassword", 110, 50, 6, 106), self)
+        self.ln2 = self.insertFixedLine("ln2",
+                PROPNAMES_LABEL,
+                (8, self.resources.resln2_value, "ln2", 6, 68, 7, 210))
+        self.btnTestConnection = self.insertButton("btnConnect", "connect",
+                PROPNAMES_BUTTON,
+                (14, HelpIds.getHelpIdString(HID_FTP_TEST), self.resources.resbtnConnect_value, "btnConnect", 12, 80, 8, 50), self)
+        self.imgStatus = self.insertImage("imgStatus",
+                ("Border", PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, "ScaleImage", "Tabstop", PropertyNames.PROPERTY_WIDTH),
+                (0, 14, 68, 80, False, False, 14))
+        self.lblStatus = self.insertLabel("lblStatus",
+                PROPNAMES_LABEL,
+                (8, self.resources.resFTPDisconnected, "lblStatus", 86, 82, 9, 99))
+        self.ln3 = self.insertFixedLine("ln3",
+                PROPNAMES_LABEL,
+                (8, self.resources.resln3_value, "ln3", 6, 100, 10, 210))
+        self.txtDir = self.insertTextField("txtDir", None,
+                (PropertyNames.PROPERTY_ENABLED, PropertyNames.PROPERTY_HEIGHT, PropertyNames.PROPERTY_HELPURL, PropertyNames.PROPERTY_NAME, PropertyNames.PROPERTY_POSITION_X, PropertyNames.PROPERTY_POSITION_Y, PropertyNames.PROPERTY_TABINDEX, "Text", PropertyNames.PROPERTY_WIDTH),
+                (False, 12, HelpIds.getHelpIdString(HID_FTP_TXT_PATH), "txtDir", 12, 113, 11, self.resources.restxtDir_value, 184), self)
+        self.btnDir = self.insertButton("btnDir", "chooseDirectory",
+                PROPNAMES_BUTTON,
+                (14, HelpIds.getHelpIdString(HID_FTP_BTN_PATH), self.resources.resbtnDir_value, "btnDir", 199, 112, 12, 16), self)
+        self.btnOK = self.insertButton("btnOK", None,
+                PROPNAMES_BUTTON2,
+                (14, HelpIds.getHelpIdString(HID_FTP_OK), self.resources.resbtnOK_value, "btnOK", 165, 142, PushButtonType_OK_value, 13, 50), self)
+        self.btnCancel = self.insertButton("btnCancel",
+                None, PROPNAMES_BUTTON2,
+                (14, HelpIds.getHelpIdString(HID_FTP_CANCEL), self.resources.resbtnCancel_value, "btnCancel", 113, 142, PushButtonType_CANCEL_value, 14, 50), self)
+        self.btnHelp = self.insertButton("btnHelp", None,
+                PROPNAMES_BUTTON2,
+                (14, "", self.resources.resbtnHelp_value, "btnHelp", 57, 142, PushButtonType_HELP_value, 15, 50), self)
+
+
+    # Make hostname, username and password text fields data aware.
+    def configure(self):
+        self.dataAware.append(UnoDataAware.attachEditControl(self, "host", self.txtHost, True))
+        self.dataAware.append(UnoDataAware.attachEditControl(self, "username", self.txtUsername, True))
+        self.dataAware.append(UnoDataAware.attachEditControl(self, "password", self.txtPassword, True))
+
+    # Shows the dialog.
+    # If the user clicks ok, changes the given CGPublish properties to the
+    # user input.
+    # @param parent a dialog to center this dialog to.
+    # @return 0 for cancel, 1 for ok.
+    # @throws Exception - well, if something goes wrong...
+    def execute(self, parent):
+        self.host = self.extractHost(self.publish.cp_URL)
+        self.username = "" if (self.publish.cp_Username == None) else self.publish.cp_Username
+        self.password = "" if (self.publish.password == None) else self.publish.password
+        self.folder = self.extractDir(self.publish.cp_URL)
+        self.setLabel(self.STATUS_UNKONWN)
+
+        self.enableTestButton()
+        self.updateUI()
+        result = self.executeDialogFromParent(parent)
+        # change the CGPublish properties
+        if (result == 1):
+            self.publish.cp_URL = "ftp://" + self.host() + self.getDir()
+            self.publish.cp_Username = self.username
+            self.publish.password = self.password
+
+        return result
+
+    # updates the hostname, username, password and
+    # directory text fields.
+    # is called uppon initialization.
+    def updateUI(self):
+        DataAware.updateUIs(self.dataAware)
+        self.setDir(self.folder)
+
+    # extract the hostname out of the url used by the
+    # publisher. This url does not include the username:password string.
+    # @param ftpUrl
+    # @return
+    def extractHost(self, ftpUrl):
+        if (ftpUrl is None or len(ftpUrl) < 6):
+            return ""
+        url = ftpUrl.substring(6)
+        i = url.indexOf("/")
+        if (i == -1):
+            return url
+        else:
+            return url.substring(0, i)
+
+    # used to get data from the CGPublish object.
+    # @param ftpUrl
+    # @return the directory portion of the ftp-url
+    def extractDir(self, ftpUrl):
+        if (ftpUrl is None or len(ftpUrl) < 6):
+            return "/"
+        url = ftpUrl.substring(6)
+        i = url.indexOf("/")
+        if (i == -1):
+            return "/"
+        else:
+            return url.substring(i)
+
+    # enables/disables the "test" button
+    # according to the status of the hostname, username, password text fields.
+    # If one of these fields is empty, the button is disabled.
+    def enableTestButton(self):
+        self.setEnabled(self.btnTestConnection, not self.isEmpty(self.host) or self.isEmpty(self.username) or self.isEmpty(self.password))
+
+    # @param s
+    # @return True if the string is None or "".
+    def isEmpty(self, s):
+        return (s is None) or (s == "")
+
+    # @return the ftp url with username and password,
+    # but without the directory portion.
+    def getAcountUrl(self):
+        return "ftp://" + self.username + ":" + self.password + "@" + self.host()
+
+    # return the host name without the "ftp://"
+    # @return
+    def host(self):
+        return self.host(self.host)
+
+    @classmethod
+    def host1(self, s):
+        return s.substring(6) if s.startswith("ftp://") else s
+
+    # @return the full ftp url including username, password and directory portion.
+    def getFullUrl(self):
+        return self.getAcountUrl() + self.folder
+
+    # First I try to connect to the full url, including directory.
+    # If an InteractiveAugmentedIOException accures, I try again,
+    # this time without the dir spec. If this works, I change the dir
+    # to "/", if not I say to the user its his problem...
+    def connect(self):
+        self.setEnabled(self.btnTestConnection, False)
+        self.setLabel(self.STATUS_CONNECTING)
+        success = False
+        try:
+            self.connect1(self.getFullUrl())
+            success = True
+        except InteractiveAugmentedIOException as iaioex:
+            try:
+                self.connect1(self.getAcountUrl())
+                self.setDir("/")
+                success = True
+            except Exception:
+                self.setLabel(self.STATUS_NO_RIGHTS)
+        except InteractiveNetworkResolveNameException as inrne:
+            self.setLabel(self.STATUS_SERVER_NOT_FOUND)
+        except AuthenticationRequest as ar:
+            self.setLabel(self.STATUS_USER_PWD_WRONG)
+        except InteractiveNetworkConnectException as incx:
+            self.setLabel(self.STATUS_HOST_UNREACHABLE)
+        except Exception:
+            self.setLabel(-1)
+            traceback.print_exc()
+
+        if (success):
+            self.setLabel(self.STATUS_OK)
+            self.setEnabled(self.btnDir, True)
+            self.setEnabled(self.btnOK, True)
+
+        self.setEnabled(self.btnTestConnection, True)
+
+
+    # To try the conenction I do some actions that
+    # seem logical to me: <br/>
+    # I get a ucb content.
+    # I list the files in this content.
+    # I call the ucb "open" command.
+    # I get the PropertyNames.PROPERTY_TITLE property of this content.
+    # @param acountUrl
+    # @throws Exception
+    def connect1(self, acountUrl):
+        content = self.ucb.getContent(self.acountUrl)
+
+        # list files in the content.
+        l = self.ucb.listFiles(self.acountUrl, None)
+
+        # open the content
+        aArg = OpenCommandArgument2()
+        aArg.Mode = OpenMode.FOLDERS # FOLDER, DOCUMENTS -> simple filter
+        aArg.Priority = 32768 # Ignored by most implementations
+
+        self.ucb.executeCommand(content, "open", aArg)
+
+        # get the title property of the content.
+        obj = self.ucb.getContentProperty(content, PropertyNames.PROPERTY_TITLE, str())
+
+    # changes the ftp subdirectory, in both
+    # the UI and the data.
+    # @param s the directory.
+    def setDir(self, s):
+        self.folder = s
+        self.txtDir.Model.Text = self.folder
+
+    # @return the ftp subdirecrtory.
+    def getDir(self):
+        return self.folder
+
+    # changes the status label to disconnected status, and
+    # disables the ok and choose-dir buttons.
+    # This method is called also when the hostname, username
+    # and passwordtext fields change.
+    def disconnect(self):
+        self.enableTestButton()
+        self.setEnabled(self.btnOK, False)
+        self.setEnabled(self.btnDir, False)
+        self.setLabel(self.STATUS_UNKONWN)
+
+    # changes the status label and icon, according to the
+    # given status
+    # @param status one opf the private status-constants.
+    # if this param is not one of them, an "unknown error" status is displayed.
+    def setLabel(self, status):
+        if status == self.STATUS_UNKONWN:
+            # not connected yet
+            self.setLabel1(self.resources.resFTPDisconnected, self.ICON_UNKNOWN)
+        elif status == self.STATUS_OK:
+            # connected!
+            self.setLabel1(self.resources.resFTPConnected, self.ICON_OK)
+        elif status == self.STATUS_USER_PWD_WRONG:
+            # wronf password
+            self.setLabel1(self.resources.resFTPUserPwdWrong, self.ICON_ERROR)
+        elif status == self.STATUS_SERVER_NOT_FOUND:
+            # problem resolving server name
+            self.setLabel1(self.resources.resFTPServerNotFound, self.ICON_ERROR)
+        elif status == self.STATUS_NO_RIGHTS:
+            # rights problem
+            self.setLabel1(self.resources.resFTPRights, self.ICON_ERROR)
+        elif status == self.STATUS_HOST_UNREACHABLE:
+            # host unreachable (firewall?)
+            self.setLabel1(self.resources.resFTPHostUnreachable, self.ICON_ERROR)
+        elif status ==  self.STATUS_CONNECTING:
+            self.setLabel1(self.resources.resConnecting, self.ICON_CONNECTING)
+        else:
+            self.setLabel1(self.resources.resFTPUnknownError, self.ICON_ERROR)
+
+    # changes the text of the status label and
+    # (TODO) the status image.
+    # @param label
+    # @param image
+    def setLabel1(self, label, image):
+        setattr(self.lblStatus.Model, PropertyNames.PROPERTY_LABEL, label)
+        setattr(self.imgStatus.Model, PropertyNames.PROPERTY_IMAGEURL, self.imageUrl(image))
+
+    def imageUrl(self, s):
+        return self.imagesDirectory + s
+
+    # called when the user clicks
+    # the choose-dir button. ("...")
+    # Opens the pickFolder dialog.
+    # checks if the returned folder is an ftp folder.
+    # sets the textbox and the data to the new selected dir.
+    def chooseDirectory(self):
+        sd = SystemDialog.createOfficeFolderDialog(self.xMSF)
+        newUrl = sd.callFolderDialog(self.resources.resFTPDirectory, "", self.getFullUrl())
+        if (newUrl is not None):
+            # if the user chose a local directory,
+            # sI do not accept it.
+            if (newUrl.startswith("ftp://")):
+                self.setDir(extractDir(newUrl))
+            else:
+                AbstractErrorHandler.showMessage(self.xMSF, self.xUnoDialog.getPeer(), self.resources.resIllegalFolder, ErrorHandler.ERROR_PROCESS_FATAL)
+
+    # practical to have such a method...
+    # @param p the publisher obejct that contains the ftp connection info.
+    # @return the full ftp url with username password and everything one needs.
+    @classmethod
+    def getFullURL1(self, p):
+        #return "ftp://" + p.Username + ":" + p.password + "@" + self.host(p.URL)
+        return "ftp://" + p.cp_Username + ":" + "" + "@" + self.host1(p.cp_URL)

-- 
To view, visit https://gerrit.libreoffice.org/2998
To unsubscribe, visit https://gerrit.libreoffice.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia5ac3202e602fa5154510c7249847713cc76692e
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: master
Gerrit-Owner: Javier Fernandez <javier.fgb at gmail.com>



More information about the LibreOffice mailing list