emailuis/nmailui/src/nmeditorcontent.cpp
changeset 54 997a02608b3a
parent 53 bf7eb7911fc5
child 59 16ed8d08d0b1
equal deleted inserted replaced
53:bf7eb7911fc5 54:997a02608b3a
    17 
    17 
    18 #include "nmuiheaders.h"
    18 #include "nmuiheaders.h"
    19 
    19 
    20 // Layout
    20 // Layout
    21 static const char *NMUI_EDITOR_BODY = "BodyTextEdit";
    21 static const char *NMUI_EDITOR_BODY = "BodyTextEdit";
    22 
    22 static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea";
       
    23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents";
       
    24 
       
    25 // Regular expression for selecting img tags with "cid" in the mail.
       
    26 static const char *NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG = 
       
    27     "(<img[^<]+(src\\s*=\\s*)(.{0,1}cid)([^<]+)(>\\s*|/>\\s*|></img>\\s*))";
       
    28 	
    23 /*!
    29 /*!
    24     Constructor
    30     Constructor
    25 */
    31 */
    26 NmEditorContent::NmEditorContent(QGraphicsItem *parent,
    32 NmEditorContent::NmEditorContent(QObject *parent,
    27                                  NmEditorView *parentView,
       
    28                                  HbDocumentLoader *documentLoader,
    33                                  HbDocumentLoader *documentLoader,
    29                                  QNetworkAccessManager &manager) :
    34                                  QNetworkAccessManager &manager,
    30     HbWidget(parent),
    35                                  NmApplication &application) :
    31     mHeaderWidget(NULL),
    36     QObject(parent),
    32     mParentView(parentView),
    37     mHeader(NULL),
    33     mEditorLayout(NULL),
    38     mMessageBodyType(NmPlainText),
    34     mMessageBodyType(PlainText),
       
    35     mEditorWidget(NULL),
    39     mEditorWidget(NULL),
    36     mBackgroundScrollArea((NmBaseViewScrollArea*)parent)
    40     mScrollArea(NULL),
    37 {
    41     mScrollAreaContents(NULL),
    38     NM_FUNCTION;
    42     mApplication(application)
    39 
    43 {
    40     // Add header area handling widget into layout
    44     NM_FUNCTION;
    41     mHeaderWidget = new NmEditorHeader(documentLoader);
    45 
       
    46     // Construct container for the header widgets
       
    47     mHeader = new NmEditorHeader(this, documentLoader);
    42 
    48 
    43     // Get pointer to body text area handling widget
    49     // Get pointer to body text area handling widget
    44     mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY));
    50     mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY));
    45     
    51     
    46     // Set body editor to use NmEditorTextDocument
    52     // Set body editor to use NmEditorTextDocument
    47     NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager);
    53     NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager);
    48     mEditorWidget->setDocument(textDocument); 
    54     mEditorWidget->setDocument(textDocument); 
    49     textDocument->setParent(mEditorWidget); // ownership changes
    55     textDocument->setParent(mEditorWidget); // ownership changes
    50 
    56 
    51     mEditorWidget->init(mBackgroundScrollArea);
    57     mScrollArea = qobject_cast<NmBaseViewScrollArea *>
    52     // we are interested in the editor widget's height changes
    58         (documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA));
    53     connect(mEditorWidget, SIGNAL(editorContentHeightChanged()), this,
    59     mScrollArea->setScrollDirections(Qt::Vertical | Qt::Horizontal);
    54         SLOT(setEditorContentHeight()));
    60     
    55 
       
    56     // Enable style picker menu item.
    61     // Enable style picker menu item.
    57     mEditorWidget->setFormatDialog(new HbFormatDialog());
    62     mEditorWidget->setFormatDialog(new HbFormatDialog());
    58 
    63 
       
    64     mScrollAreaContents =
       
    65         qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS));
       
    66     
    59     // Create signal slot connections
    67     // Create signal slot connections
    60     createConnections();
    68     createConnections();
    61 }
    69 }
    62 
    70 
    63 /*!
    71 /*!
    64     Destructor
    72     Destructor
    65 */
    73 */
    66 NmEditorContent::~NmEditorContent()
    74 NmEditorContent::~NmEditorContent()
    67 {
    75 {
    68     NM_FUNCTION;
    76     NM_FUNCTION;
    69     
       
    70    delete mHeaderWidget;
       
    71 }
    77 }
    72 
    78 
    73 /*!
    79 /*!
    74     Fill message data into header and body fileds. If reply envelopw is
    80     Fill message data into header and body fileds. If reply envelopw is
    75     present, reply header is generated and set to editor. Reply
    81     present, reply header is generated and set to editor. Reply
    76     envelope ownership is not transferred here.
    82     envelope ownership is not transferred here.
    77  */
    83  */
    78 void NmEditorContent::setMessageData(const NmMessage &originalMessage,
    84 void NmEditorContent::setMessageData(const NmMessage &originalMessage, 
    79                                      bool createReplyHeader)
    85                                      NmUiEditorStartMode &editorStartMode)
    80 {
    86 {
    81     NM_FUNCTION;
    87     NM_FUNCTION;
    82     
    88     
    83     QString bodyContent;
    89     QString bodyContent;
    84     
    90     
    85     // We create the "reply" header (also for forward message), but not to draft message.
    91     // Create the "reply" header (also for forward message)
    86     if (mEditorWidget && createReplyHeader) {          
    92     if (editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll || 
    87         QTextCursor cursor = mEditorWidget->textCursor();
    93         editorStartMode==NmUiEditorForward) {
    88         cursor.setPosition(0);
    94         bodyContent.append(NmUtilities::createReplyHeader(originalMessage.envelope()));
    89         cursor.insertHtml(NmUtilities::createReplyHeader(originalMessage.envelope()));
    95     }
    90     }
       
    91     // Take reply header as html format.
       
    92     bodyContent.append(mEditorWidget->toHtml());
       
    93     
    96     
    94     // Check which part is present. Html or plain text part. We use the original message parts.
    97     // Check which part is present. Html or plain text part. We use the original message parts.
    95     const NmMessagePart *htmlPart = originalMessage.htmlBodyPart();
    98     const NmMessagePart *htmlPart = originalMessage.htmlBodyPart();
    96     const NmMessagePart *plainPart = originalMessage.plainTextBodyPart();
    99     const NmMessagePart *plainPart = originalMessage.plainTextBodyPart();
    97  
   100  
    98     if (htmlPart && mEditorWidget) {
   101     if (htmlPart) {
    99         bodyContent.append(htmlPart->textContent());
   102         bodyContent.append(htmlPart->textContent());
       
   103         if(editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll ) {
       
   104             removeEmbeddedImages(bodyContent);
       
   105         }
   100         emit setHtml(bodyContent);
   106         emit setHtml(bodyContent);
   101         mMessageBodyType = HTMLText;
   107         mMessageBodyType = NmHTMLText;
   102     }
   108     }
   103     else if (plainPart) {
   109     else if (plainPart) {
   104         // Plain text part was present, set it to HbTextEdit
   110         // Plain text part was present, set it to HbTextEdit
   105         bodyContent.append(plainPart->textContent());
   111         bodyContent.append(plainPart->textContent());
   106         emit setPlainText(bodyContent);
   112         emit setPlainText(bodyContent);
   107         mMessageBodyType = PlainText;
   113         mMessageBodyType = NmPlainText;
   108     }
   114     }
   109 }  
   115 }  
   110 
   116 
   111 /*!
   117 /*!
   112    This method set new height for the editor content when header or body field
       
   113    height has been changed.
       
   114  */
       
   115 void NmEditorContent::setEditorContentHeight()
       
   116 {
       
   117     NM_FUNCTION;
       
   118     
       
   119 	const QSizeF reso = HbDeviceProfile::current().logicalSize();
       
   120     qreal containerHeight = mEditorWidget->contentHeight() + mHeaderWidget->headerHeight();
       
   121     if (containerHeight < reso.height()) {
       
   122         //Currently content height is too long because Chrome hiding is not supported.
       
   123         //Fix this when Chrome works.
       
   124         containerHeight = reso.height();
       
   125         qreal bodyContentHeight =
       
   126             reso.height() - mHeaderWidget->headerHeight();
       
   127         mEditorWidget->setPreferredHeight(bodyContentHeight);
       
   128         mEditorWidget->setMaximumHeight(bodyContentHeight);
       
   129     }
       
   130     mParentView->scrollAreaContents()->setMinimumHeight(containerHeight);
       
   131     mParentView->scrollAreaContents()->setMaximumHeight(containerHeight);
       
   132     mBackgroundScrollArea->setMaximumHeight(containerHeight);
       
   133 }
       
   134 
       
   135 /*!
       
   136    This method creates all needed signal-slot connections
   118    This method creates all needed signal-slot connections
   137  */
   119  */
   138 void NmEditorContent::createConnections()
   120 void NmEditorContent::createConnections()
   139 {
   121 {
   140     NM_FUNCTION;
   122     NM_FUNCTION;
   141     
   123     
   142     // Body edit widget is also interested about bg scroll position change
       
   143     connect(mBackgroundScrollArea, SIGNAL(scrollPositionChanged(QPointF)),
       
   144             mEditorWidget, SLOT(updateScrollPosition(QPointF)));
       
   145     // Signal for setting HbTextEdit widgets html content
   124     // Signal for setting HbTextEdit widgets html content
   146     connect(this, SIGNAL(setHtml(QString)),
   125     connect(this, SIGNAL(setHtml(QString)),
   147             mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection);
   126             mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection);
       
   127 
   148     // Signal for setting HbTextEdit widgets plain text content
   128     // Signal for setting HbTextEdit widgets plain text content
   149     connect(this, SIGNAL(setPlainText(QString)),
   129     connect(this, SIGNAL(setPlainText(QString)),
   150             mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection);
   130             mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection);
       
   131 
   151     // Inform text edit widget that header height has been changed
   132     // Inform text edit widget that header height has been changed
   152     connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)),
   133     connect(mHeader, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()),
   153             mEditorWidget, SLOT(setHeaderHeight(int)));
   134         Qt::QueuedConnection);
       
   135 
       
   136     // we are interested in the document's height changes
       
   137     connect(mEditorWidget->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), this,
       
   138         SLOT(setEditorContentHeight()), Qt::QueuedConnection);
       
   139 
       
   140     // We need to update the scroll position according the editor's cursor position
       
   141     connect(mHeader->toEdit(), SIGNAL(cursorPositionChanged(int, int)), this, 
       
   142         SLOT(ensureCursorVisibility()), Qt::QueuedConnection);
       
   143     connect(mHeader->ccEdit(), SIGNAL(cursorPositionChanged(int, int)), this, 
       
   144         SLOT(ensureCursorVisibility()), Qt::QueuedConnection);
       
   145     connect(mHeader->bccEdit(), SIGNAL(cursorPositionChanged(int, int)), this, 
       
   146         SLOT(ensureCursorVisibility()), Qt::QueuedConnection);
       
   147     connect(mHeader->subjectEdit(), SIGNAL(cursorPositionChanged(int, int)), this, 
       
   148         SLOT(ensureCursorVisibility()), Qt::QueuedConnection);
       
   149     connect(mEditorWidget, SIGNAL(cursorPositionChanged(int, int)), this, 
       
   150         SLOT(ensureCursorVisibility()), Qt::QueuedConnection);
       
   151 
       
   152     // listen to the parent's (NmEditorView) size changes which happen eg. when VKB is opened/closed
       
   153     connect(parent(), SIGNAL(sizeChanged()), this, SLOT(ensureCursorVisibility()),
       
   154         Qt::QueuedConnection);
   154 }
   155 }
   155 
   156 
   156 /*!
   157 /*!
   157     Return pointer to the email body text edit widget
   158     Return pointer to the email body text edit widget
   158  */
   159  */
   159 NmEditorTextEdit* NmEditorContent::editor() const
   160 NmEditorTextEdit *NmEditorContent::editor() const
   160 {
   161 {
   161     NM_FUNCTION;
   162     NM_FUNCTION;
   162     
   163     
   163     return mEditorWidget;
   164     return mEditorWidget;
   164 }
   165 }
   165 
   166 
   166 /*!
   167 /*!
   167     Return pointer to the header widget
   168     Return pointer to the header widget
   168  */
   169  */
   169 NmEditorHeader* NmEditorContent::header() const
   170 NmEditorHeader *NmEditorContent::header() const
   170 {
   171 {
   171     NM_FUNCTION;
   172     NM_FUNCTION;
   172     
   173     
   173     return mHeaderWidget;
   174     return mHeader;
   174 }
   175 }
   175 
   176 
       
   177 /*!
       
   178     This slot is called when header widget height has been changed. Function performs
       
   179     the repositioning of the body field and resizing of the editor and content area.
       
   180  */
       
   181 void NmEditorContent::setEditorContentHeight()
       
   182 {
       
   183     NM_FUNCTION;
       
   184     
       
   185     // the height of the margin between the title bar and the header
       
   186     qreal topMargin = 0;
       
   187     HbStyle().parameter("hb-param-margin-gene-top", topMargin);
       
   188     
       
   189     // header height
       
   190     qreal headerHeight = mHeader->headerHeight();
       
   191 
       
   192     // body area editor's document height with margins added
       
   193     qreal documentHeightAndMargins = mEditorWidget->document()->size().height() +
       
   194         (mEditorWidget->document()->documentMargin() * 2);
       
   195 
       
   196     // chrome height
       
   197     qreal chromeHeight = 0;
       
   198     HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight);
       
   199     
       
   200     // screen height
       
   201     qreal screenHeight = mApplication.screenSize().height();
       
   202 
       
   203     // set min size for the body area so that at least the screen area is always filled
       
   204     qreal bodyAreaMinSize = screenHeight - chromeHeight - topMargin - headerHeight;
       
   205     
       
   206     qreal bodyAreaSize = fmax(bodyAreaMinSize, documentHeightAndMargins);
       
   207 
       
   208     mScrollAreaContents->setPreferredHeight(topMargin + headerHeight + bodyAreaSize);
       
   209 }
       
   210 
       
   211 /*!
       
   212     This slot is called when the cursor visibility has to be ensured ie. the scroll position is 
       
   213     adjusted so that the cursor can be seen.
       
   214 */
       
   215 void NmEditorContent::ensureCursorVisibility()
       
   216 {
       
   217     NM_FUNCTION;
       
   218 
       
   219     // check which of the editors has the focus and get the x/y coordinates for the cursor position
       
   220     QGraphicsWidget *focused = mScrollAreaContents->focusWidget();
       
   221     
       
   222     if (focused) {
       
   223         QRectF localRect(0, 0, 0, 0);
       
   224         bool notFound = false;
       
   225         
       
   226         if (focused == mHeader->toEdit()) {
       
   227             localRect = mHeader->toEdit()->rectForCursorPosition();
       
   228         }
       
   229         else if (focused == mHeader->ccEdit()) {
       
   230             localRect = mHeader->ccEdit()->rectForCursorPosition();
       
   231         }
       
   232         else if (focused == mHeader->bccEdit()) {
       
   233             localRect = mHeader->bccEdit()->rectForCursorPosition();
       
   234         }
       
   235         else if (focused == mHeader->subjectEdit()) {
       
   236             localRect = mHeader->subjectEdit()->rectForCursorPosition();
       
   237         }
       
   238         else if (focused == mEditorWidget) {
       
   239             localRect = mEditorWidget->rectForCursorPosition();
       
   240         }
       
   241         else {
       
   242             notFound = true;
       
   243         }
       
   244 
       
   245         if (!notFound) {
       
   246             QPointF topLeftPos = focused->mapToItem(mScrollAreaContents, localRect.topLeft());
       
   247             QPointF bottomRightPos =
       
   248                 focused->mapToItem(mScrollAreaContents, localRect.bottomRight());
       
   249             qreal marginRight = 0;
       
   250             HbStyle().parameter("hb-param-margin-gene-right", marginRight);
       
   251             bottomRightPos.rx() += marginRight;
       
   252             mScrollArea->ensureVisible(topLeftPos);
       
   253             mScrollArea->ensureVisible(bottomRightPos);
       
   254         }
       
   255     }
       
   256 }
       
   257 /*!
       
   258     Removes embedded images from the message body
       
   259  */
       
   260 void NmEditorContent::removeEmbeddedImages(QString &bodyContent)
       
   261 {
       
   262     NM_FUNCTION;
       
   263  
       
   264     QRegExp regExp(NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG, Qt::CaseInsensitive);
       
   265     bodyContent.remove(regExp);
       
   266 }