Quellcode durchsuchen

ENH: Added Copy metadata button to DICOM metadata widget (#727)

* ENH: Added Copy metadata button to DICOM metadata widget

Added "Copy metadata" button (next to "Copy path" button) in the DICOM metadata browser (ctkDICOMObjectListWidget) to copy all metadata to the clipboard.
It is useful for collecting information from users when they reporting DICOM loading errors.

Also added tooltip for the existing, very useful, but hard-to-discover feature: if user clicks on a tag then its definition is displayed at http://dicomlookup.com.

* ENH: Updated based on code review comments
Andras Lasso vor 8 Jahren
Ursprung
Commit
253a54aef0

+ 20 - 27
Libs/DICOM/Widgets/Resources/UI/ctkDICOMObjectListWidget.ui

@@ -6,8 +6,8 @@
    <rect>
    <rect>
     <x>0</x>
     <x>0</x>
     <y>0</y>
     <y>0</y>
-    <width>312</width>
-    <height>206</height>
+    <width>486</width>
+    <height>297</height>
    </rect>
    </rect>
   </property>
   </property>
   <property name="windowTitle">
   <property name="windowTitle">
@@ -20,18 +20,6 @@
       <layout class="QHBoxLayout" name="horizontalLayout">
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
        <item>
         <widget class="QLabel" name="label">
         <widget class="QLabel" name="label">
-         <property name="minimumSize">
-          <size>
-           <width>70</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>70</width>
-           <height>16777215</height>
-          </size>
-         </property>
          <property name="text">
          <property name="text">
           <string>File Path:</string>
           <string>File Path:</string>
          </property>
          </property>
@@ -39,6 +27,12 @@
        </item>
        </item>
        <item>
        <item>
         <widget class="QLabel" name="currentPathLabel">
         <widget class="QLabel" name="currentPathLabel">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
          <property name="text">
          <property name="text">
           <string/>
           <string/>
          </property>
          </property>
@@ -46,18 +40,6 @@
        </item>
        </item>
        <item>
        <item>
         <widget class="QPushButton" name="copyPathPushButton">
         <widget class="QPushButton" name="copyPathPushButton">
-         <property name="minimumSize">
-          <size>
-           <width>100</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>100</width>
-           <height>16777215</height>
-          </size>
-         </property>
          <property name="toolTip">
          <property name="toolTip">
           <string>Copy the file full path to the clipboard.</string>
           <string>Copy the file full path to the clipboard.</string>
          </property>
          </property>
@@ -66,6 +48,13 @@
          </property>
          </property>
         </widget>
         </widget>
        </item>
        </item>
+       <item>
+        <widget class="QPushButton" name="copyMetadataPushButton">
+         <property name="text">
+          <string>Copy Metadata</string>
+         </property>
+        </widget>
+       </item>
       </layout>
       </layout>
      </item>
      </item>
      <item>
      <item>
@@ -79,7 +68,11 @@
       <layout class="QHBoxLayout" name="horizontalLayout_3"/>
       <layout class="QHBoxLayout" name="horizontalLayout_3"/>
      </item>
      </item>
      <item>
      <item>
-      <widget class="QTreeView" name="dcmObjectTreeView"/>
+      <widget class="QTreeView" name="dcmObjectTreeView">
+       <property name="toolTip">
+        <string>Double-click Tag to show its definition.</string>
+       </property>
+      </widget>
      </item>
      </item>
     </layout>
     </layout>
    </item>
    </item>

+ 63 - 2
Libs/DICOM/Widgets/ctkDICOMObjectListWidget.cpp

@@ -43,6 +43,7 @@ public:
   ~ctkDICOMObjectListWidgetPrivate();
   ~ctkDICOMObjectListWidgetPrivate();
   void populateDICOMObjectTreeView(const QString& fileName);
   void populateDICOMObjectTreeView(const QString& fileName);
   void setPathLabel(const QString& currentFile);
   void setPathLabel(const QString& currentFile);
+  QString dicomObjectModelAsString(QModelIndex parent = QModelIndex(), int indent = 0);
 
 
   QString currentFile;
   QString currentFile;
   QStringList fileList;
   QStringList fileList;
@@ -76,6 +77,49 @@ void ctkDICOMObjectListWidgetPrivate::setPathLabel(const QString& currentFile)
   currentPathLabel->setText(currentFile);
   currentPathLabel->setText(currentFile);
 }
 }
 
 
+// --------------------------------------------------------------------------
+QString ctkDICOMObjectListWidgetPrivate::dicomObjectModelAsString(QModelIndex parent /*=QModelIndex()*/, int indent /*=0*/)
+{
+  QString dump;
+  QString indentString(indent, '\t'); // add tab characters, (indent) number of times
+#ifdef WIN32
+  QString newLine = "\r\n";
+#else
+  QString newLine = "\n";
+#endif
+  for (int r = 0; r < this->dicomObjectModel->rowCount(parent); ++r)
+    {
+    dump += indentString;
+    for (int c = 0; c < this->dicomObjectModel->columnCount(); ++c)
+      {
+      QModelIndex index = this->dicomObjectModel->index(r, c, parent);
+      QString name = this->dicomObjectModel->data(index).toString();
+      if (c == 0)
+        {
+        // Replace round brackets by square brackets.
+        // If the text is copied into Excel, Excel would recognize tag (0008,0012)
+        // as a negative number (-80,012). Instead, [0008,0012] is displayed fine.
+        name.replace('(', '[');
+        name.replace(')', ']');
+        dump += name;
+        }
+      else
+        {
+        dump += "\t" + name;
+        }
+      
+      }
+    dump += newLine;
+    // here is your applicable code
+    QModelIndex index0 = this->dicomObjectModel->index(r, 0, parent);
+    if (this->dicomObjectModel->hasChildren(index0))
+      {
+      dump += dicomObjectModelAsString(index0, indent+1);
+      }
+    }
+  return dump;
+}
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 // ctkDICOMObjectListWidget methods
 // ctkDICOMObjectListWidget methods
 
 
@@ -95,6 +139,7 @@ ctkDICOMObjectListWidget::ctkDICOMObjectListWidget(QWidget* _parent):Superclass(
   connect(d->dcmObjectTreeView, SIGNAL(doubleClicked(const QModelIndex&))
   connect(d->dcmObjectTreeView, SIGNAL(doubleClicked(const QModelIndex&))
                                ,this, SLOT(openLookupUrl(const QModelIndex&)));
                                ,this, SLOT(openLookupUrl(const QModelIndex&)));
   connect(d->copyPathPushButton , SIGNAL(clicked(bool)),this, SLOT(copyPath()));
   connect(d->copyPathPushButton , SIGNAL(clicked(bool)),this, SLOT(copyPath()));
+  connect(d->copyMetadataPushButton, SIGNAL(clicked(bool)), this, SLOT(copyMetadata()));
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -116,11 +161,10 @@ void ctkDICOMObjectListWidget::setFileList(const QStringList& fileList)
 {
 {
   Q_D(ctkDICOMObjectListWidget);
   Q_D(ctkDICOMObjectListWidget);
   d->fileList = fileList;
   d->fileList = fileList;
-  if (d-> fileList.size()> 0)
+  if (d->fileList.size() > 0)
     {
     {
     d->currentFile = d->fileList[0];
     d->currentFile = d->fileList[0];
     d->setPathLabel(d->currentFile );
     d->setPathLabel(d->currentFile );
-    d->currentPathLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
     d->populateDICOMObjectTreeView(d->currentFile );
     d->populateDICOMObjectTreeView(d->currentFile );
     d->fileSliderWidget->setMaximum(fileList.size()-1);
     d->fileSliderWidget->setMaximum(fileList.size()-1);
     }
     }
@@ -167,3 +211,20 @@ void ctkDICOMObjectListWidget::copyPath()
   QClipboard *clipboard = QApplication::clipboard();
   QClipboard *clipboard = QApplication::clipboard();
   clipboard->setText(d->currentFile);
   clipboard->setText(d->currentFile);
 }
 }
+
+// --------------------------------------------------------------------------
+
+QString ctkDICOMObjectListWidget::metadataAsText()
+{
+  Q_D(ctkDICOMObjectListWidget);
+  return d->dicomObjectModelAsString();
+}
+
+// --------------------------------------------------------------------------
+
+void ctkDICOMObjectListWidget::copyMetadata()
+{
+  Q_D(ctkDICOMObjectListWidget);
+  QClipboard *clipboard = QApplication::clipboard();
+  clipboard->setText(metadataAsText());
+}

+ 4 - 0
Libs/DICOM/Widgets/ctkDICOMObjectListWidget.h

@@ -44,6 +44,9 @@ public:
   QString currentFile();
   QString currentFile();
   QStringList fileList();
   QStringList fileList();
 
 
+  /// Get metadata tree as plain text
+  QString metadataAsText();
+
 protected:
 protected:
   QScopedPointer<ctkDICOMObjectListWidgetPrivate> d_ptr;
   QScopedPointer<ctkDICOMObjectListWidgetPrivate> d_ptr;
 
 
@@ -62,6 +65,7 @@ protected Q_SLOTS:
   void openLookupUrl(const QModelIndex&);
   void openLookupUrl(const QModelIndex&);
   void updateWidget();
   void updateWidget();
   void copyPath();
   void copyPath();
+  void copyMetadata();
 };
 };
 
 
 #endif
 #endif