In that case, the patch becomes much more complicated. 

We have to modify the query-replace-map in replace.el itself as we cannot access the internal variables required to printed this message in isearch-style with (sit-for 1):

(message query-replace-in-progress-message
                                    (query-replace-descr from-string)
                                    (query-replace-descr replacement-presentation)
                                    query-message-momentary)

Here: from-string, replacement-presentation are internal variables and cannot be used in a function defined outside that (cond ..) form. So the earlier approach to define a function externally to toggle the case and to bind that to query-replace-map from outside does not apply (if we want to flash the case fold toggle info momentarily as done in isearch). Even the replacement-presentation was in a (let .. ) form not accessible to the (cond ..) form and so I moved it to an outer (let ..) form as seen in the below patch.

I tested this out and the M-c and M-r bindings work great. It now also gives clear info on what the user should expect after that binding is used.
Please give it a try. 

I have still kept this line

 (def (call-interactively def)) ; User-defined key, invoke it.

as it could be useful to bind any other function from outside that does not need internal variables.

--- replace.el 2015-06-02 23:21:42.631715000 -0400
+++ replace-editted.el 2015-06-02 23:32:47.754001000 -0400
@@ -1834,6 +1834,8 @@
     (define-key map [M-next] 'scroll-other-window)
     (define-key map [?\C-\M-\S-v] 'scroll-other-window-down)
     (define-key map [M-prior] 'scroll-other-window-down)
+    (define-key map "\M-c" 'toggle-query-case)
+    (define-key map "\M-r" 'toggle-replace-preserve-case)
     ;; Binding ESC would prohibit the M-v binding.  Instead, callers
     ;; should check for ESC specially.
     ;; (define-key map "\e" 'exit-prefix)
@@ -2100,12 +2102,14 @@
          ;; (match-data); otherwise it is t if a match is possible at point.
          (match-again t)
 
-         (message
+         (query-replace-in-progress-message
           (if query-flag
               (apply 'propertize
                      (substitute-command-keys
-                      "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ")
-                     minibuffer-prompt-properties))))
+                      (concat "Query replacing %s with %s: "
+                              "(\\<query-replace-map>\\[help] for help) %s "))
+                     minibuffer-prompt-properties)))
+         (query-message-momentary ""))
 
     ;; If region is active, in Transient Mark mode, operate on region.
     (if backward
@@ -2251,7 +2255,7 @@
                          noedit real-match-data backward)
                         replace-count (1+ replace-count)))
               (undo-boundary)
-              (let (done replaced key def)
+              (let (done replaced key def replacement-presentation)
                 ;; Loop reading commands until one of them sets done,
                 ;; which means it has finished handling this
                 ;; occurrence.  Any command that sets `done' should
@@ -2266,17 +2270,18 @@
                    regexp-flag delimited-flag case-fold-search backward)
                   ;; Bind message-log-max so we don't fill up the message log
                   ;; with a bunch of identical messages.
-                  (let ((message-log-max nil)
-                        (replacement-presentation
-                         (if query-replace-show-replacement
-                             (save-match-data
-                               (set-match-data real-match-data)
-                               (match-substitute-replacement next-replacement
-                                                             nocasify literal))
-                           next-replacement)))
-                    (message message
+                  (let ((message-log-max nil))
+                    (setq replacement-presentation
+                          (if query-replace-show-replacement
+                              (save-match-data
+                                (set-match-data real-match-data)
+                                (match-substitute-replacement next-replacement
+                                                              nocasify literal))
+                            next-replacement))
+                    (message query-replace-in-progress-message
                              (query-replace-descr from-string)
-                             (query-replace-descr replacement-presentation)))
+                             (query-replace-descr replacement-presentation)
+                             query-message-momentary))
                   (setq key (read-event))
                   ;; Necessary in case something happens during read-event
                   ;; that clobbers the match data.
@@ -2404,6 +2409,51 @@
                          (replace-dehighlight)
                          (save-excursion (recursive-edit))
                          (setq replaced t))
+
+                        ((eq def 'toggle-query-case)
+                         (setq case-fold-search (not case-fold-search))
+                         (let ((message-log-max nil)
+                               (query-message-momentary
+                                (concat "["
+                                        (if case-fold-search
+                                            "case insensitive search"
+                                          "Case Sensitive Search")
+                                        "]")))
+                           (message query-replace-in-progress-message
+                                    (query-replace-descr from-string)
+                                    (query-replace-descr replacement-presentation)
+                                    query-message-momentary)
+                           (sit-for 1)))
+
+                        ((eq def 'toggle-replace-preserve-case)
+                         (let ((message-log-max nil)
+                               (nocasify-value-reason "")
+                               query-message-momentary)
+                           (setq nocasify (not nocasify))
+                           (cond
+                            ((null case-fold-search)
+                             (setq nocasify nil)
+                             (setq nocasify-value-reason ", as case-fold-search is nil"))
+                            ((null (isearch-no-upper-case-p from-string regexp-flag))
+                             (setq nocasify nil)
+                             (setq nocasify-value-reason ", as FROM-STRING has an upper case char."))
+                            ((null (isearch-no-upper-case-p next-replacement regexp-flag))
+                             (setq nocasify t)
+                             (setq nocasify-value-reason ", as REPLACEMENT has an upper case char.")))
+                           (setq query-message-momentary
+                                 (concat "[Replaced text case will "
+                                         (if nocasify "NOT " "")
+                                         "be preserved"
+                                         nocasify-value-reason
+                                         "]"))
+                           (message query-replace-in-progress-message
+                                    (query-replace-descr from-string)
+                                    (query-replace-descr replacement-presentation)
+                                    query-message-momentary)
+                           (sit-for 1.5)))
+
+                        (def (call-interactively def)) ; User-defined key, invoke it.
+
                         ;; Note: we do not need to treat `exit-prefix'
                         ;; specially here, since we reread
                         ;; any unrecognized character.


On Tue, Jun 2, 2015 at 6:51 PM Drew Adams <drew.adams@oracle.com> wrote:
> > +                  ;; Show whether `case-fold-search' is `t' or `nil'
> > +                  (if case-fold-search "[case] " "[CaSe] ")
>
> Maybe we should use the same message about case-folding like in
> isearch?

The msg should somehow indicate that what is involved here is (only)
case-sensitivity wrt FROM (i.e., wrt search, not replacement).  Not
sure what the best way to do that would be.

IOW, there is more than one use of case sensitivity here, unlike
the case for search.  There is what `case-fold-search' controls (the
search), and there is what `case-replace' controls (the replacement).
And then there is what happens for the replacement according to the
case of FROM.

---

BTW, we might consider binding a key to toggle case sensitivity for
search as part of this bug fix (i.e., not just fixing `perform-replace'
so it respects keys that user might bind).  In that case, maybe the
same key we use in Isearch (`M-c') would be a good choice.

---

BTW2, I think that Emacs manual node `Replacement and Case' is confusing.
The first three paragraphs (2/3 of the node), for instance:

 If the first argument of a replace command is all lower case, the
 command ignores case while searching for occurrences to
 replace--provided `case-fold-search' is non-`nil'.  If
 `case-fold-search' is set to `nil', case is always significant in all
 searches.

  An upper-case letter anywhere in the incremental search string makes
  the search case-sensitive.  Thus, searching for `Foo' does not find
  `foo' or `FOO'.  This applies to regular expression search as well as
  to string search.  The effect ceases if you delete the upper-case
  letter from the search string.

  If you set the variable `case-fold-search' to `nil', then all
  letters must match exactly, including case.  This is a per-buffer
  variable; altering the variable normally affects only the current
  buffer, unless you change its default value.  *Note Locals::.  This
  variable applies to nonincremental searches also, including those
  performed by the replace commands (*note Replace::) and the minibuffer
  history matching commands (*note Minibuffer History::).

These paragraphs really say only that the search part of replace commands
acts normally: `case-fold-search' governs.  They should be removed or
changed to say just that.  Leaving them as they are just confuses readers, IMO.