title: Is there some way to delay (or stream) clipboard operations in AWT / Swing?
body: <p>I have a table with a million rows.</p>
  
  <p>If I select all rows and Copy, it takes approximately 5 minutes before responsiveness returns to the GUI and before I can paste it into another application. This is less than great, so I started looking for improvements.</p>
  
  <p>If I make an alternative thread-safe TableModel, then I can background the operation of building the string and then push to the clipboard (on the EDT, if need be). Then the GUI is responsive, but it is still 5 minutes before I can paste into another application, which in some ways is a worse experience, because at least when it blocked the EDT, I was able to tell when the operation finished. I know I could add GUI feedback for it, but it seems wrong for an action like Copy.</p>
  
  <p>If I look at the same thing happening between native applications, I notice that I can copy an enormous amount of data from one application with no delay. I can then immediately paste it into another application with no delay, but just with the caveat that it can take a long time for <em>all</em> the information to end up in there. For instance, if I paste huge text from TextEdit into Terminal, it seems to do this a bit at a time somehow.</p>
  
  <p>Is there some way to do that in AWT as well?</p>
  
  <p>I attempted to do it by only declaring the alternate flavours returning <code>Reader</code> and <code>InputStream</code>, but it turns out that even if you do this, it asks for the reader one, fetches the reader and then immediately reads the entire stream, storing it as a string. So this just moves the 5 minute delay to code inside the JRE, solving nothing. This is also fairly stupid, because there is this whole framework around what type of data transfer methods your <code>Transferable</code> supports, yet no matter which type you expose, the system seems to convert it down to the same type, which in the best case will take forever to build, or in the worst case will run you out of heap.</p>
  
  <p>Maybe there is a type which doesn't though, so I thought I'd post this question to ask whether anyone knows.</p>
  
  <p>Example of one <code>TransferHandler</code>, although the built-in one on <code>JTable</code> itself exhibits the same issue.</p>
  
  <pre><code>private class CombinedTransferHandler extends TransferHandler {
      @Override
      protected Transferable createTransferable(JComponent component) {
          if (component instanceof JTable) {
              JTable table = (JTable) component;
  
              int[] rows = table.getSelectedRows();
              if (!table.getRowSelectionAllowed()) {
                  int rowCount = table.getRowCount();
  
                  rows = new int[rowCount];
                  for (int counter = 0; counter &lt; rowCount; counter++) {
                      rows[counter] = counter;
                  }
              }
  
              // columns omitted because we know we use all
              return new BasicTransferable(getPlainData(rows), null);
          }
          return null;
      }
  
      @Override
      public int getSourceActions(JComponent c) {
          return COPY;
      }
  
      private String getPlainData(int[] rows) {
          StringBuilder result = new StringBuilder();
  
          int staticColumnCount = staticTable.getColumnCount();
          int mainColumnCount = mainTable.getColumnCount();
          for (int row : rows) {
              for (int viewColumn = 0; viewColumn &lt; staticColumnCount;
                   viewColumn++) {
                  if (viewColumn &gt; 0) {
                      result.append('\t');
                  }
  
                  Object value = staticTable.getValueAt(row, viewColumn);
                  value = (value == null) ? "" : value.toString();
                  result.append(value);
              }
  
              for (int viewColumn = 0; viewColumn &lt; mainColumnCount;
                   viewColumn++) {
                  if (staticColumnCount &gt; 0 || viewColumn &gt; 0) {
                      result.append('\t');
                  }
  
                  Object value = mainTable.getValueAt(row, viewColumn);
                  value = (value == null) ? "" : value.toString();
                  result.append(value);
              }
  
              result.append('\n');
          }
  
          return result.toString();
      }
  }
  </code></pre>