Subversion Repositories svn.mios32

Rev

Rev 1763 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1542 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: MiosFileBrowser.cpp 2180 2015-06-14 19:21:59Z tk $
3
/*
4
 * File browser for MIOS32 applications
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2012 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
#include "MiosFileBrowser.h"
16
#include "MiosStudio.h"
17
 
18
//==============================================================================
19
class MiosFileBrowserFileItem
20
{
21
public:
1545 tk 22
    String parentPath;
1542 tk 23
    String name;
24
    bool isDirectory;
25
 
26
    OwnedArray<MiosFileBrowserFileItem> childs;
27
 
1545 tk 28
    MiosFileBrowserFileItem(String _parentPath, String _itemName, bool _isDirectory)
29
        : parentPath(_parentPath)
30
        , name(_itemName)
1542 tk 31
        , isDirectory(_isDirectory)
32
    {
33
    }
34
 
35
    ~MiosFileBrowserFileItem()
36
    {
37
    }
38
 
1545 tk 39
    MiosFileBrowserFileItem* createChild(String parentPath, String childName, bool isDirectory) {
40
        MiosFileBrowserFileItem* child = new MiosFileBrowserFileItem(parentPath, childName, isDirectory);
1542 tk 41
        childs.add(child);
1545 tk 42
        return child;
1542 tk 43
    }
44
};
45
 
46
 
47
//==============================================================================
48
class MiosFileBrowserItem : public TreeViewItem
49
{
50
public:
51
    MiosFileBrowserFileItem *fileItem;
52
    MiosFileBrowser* browser;
53
 
54
    MiosFileBrowserItem(MiosFileBrowserFileItem *_fileItem, MiosFileBrowser* _browser)
55
        : fileItem(_fileItem)
56
        , browser(_browser)
57
    {
58
    }
59
 
60
    ~MiosFileBrowserItem()
61
    {
62
    }
63
 
64
    int getItemWidth() const
65
    {
66
        return 100;
67
    }
68
 
1724 tk 69
    String getUniqueName() const
1542 tk 70
    {
1545 tk 71
        if( fileItem->parentPath.compare(T("/")) == 0 ) {
72
            return T("/") + fileItem->name;
73
        } else {
74
            if( fileItem->name.compare(T("/")) == 0 )
75
                return T("/");
76
            else
77
                return fileItem->parentPath + T("/") + fileItem->name;
78
        }
1542 tk 79
    }
80
 
81
    bool mightContainSubItems()
82
    {
83
        return fileItem->isDirectory;
84
    }
85
 
86
    void paintItem (Graphics& g, int width, int height)
87
    {
88
        // if this item is selected, fill it with a background colour..
89
        if( isSelected() )
90
            g.fillAll(Colours::blue.withAlpha (0.3f));
91
 
92
        // use a "colour" attribute in the xml tag for this node to set the text colour..
93
        g.setColour(Colour(0xff000000));
94
 
95
        g.setFont(height * 0.7f);
96
 
97
        // draw the item name
98
        String name(fileItem->name);
99
        g.drawText(name,
100
                   4, 0, width - 4, height,
101
                   Justification::centredLeft, true);
102
    }
103
 
104
    void itemOpennessChanged (bool isNowOpen)
105
    {
106
        if( isNowOpen ) {
107
            // if we've not already done so, we'll now add the tree's sub-items. You could
108
            // also choose to delete the existing ones and refresh them if that's more suitable
109
            // in your app.
110
            if( getNumSubItems() == 0 ) {
111
                for(int i=0; i<fileItem->childs.size(); ++i) {
1763 tk 112
                    MiosFileBrowserItem* item = new MiosFileBrowserItem(fileItem->childs[i], browser);
113
 
114
                    // sorting
115
                    int pos;
116
                    for(pos=0; pos<getNumSubItems(); ++pos) {
117
                        if( getSubItem(pos)->getUniqueName().compareIgnoreCase(item->getUniqueName()) > 0 )
118
                            break;
119
                    }
120
                    if( pos >= getNumSubItems() )
121
                        addSubItem(item);
122
                    else
123
                        addSubItem(item, pos);
1542 tk 124
                }
125
            }
126
        } else {
127
            // in this case, we'll leave any sub-items in the tree when the node gets closed,
128
            // though you could choose to delete them if that's more appropriate for
129
            // your application.
130
        }
131
    }
132
 
133
 
134
    void itemClicked (const MouseEvent& e)
135
    {
1555 tk 136
        if( getOwnerView()->isEnabled() )
137
            browser->treeItemClicked(this);
1542 tk 138
    }
139
 
140
    void itemDoubleClicked (const MouseEvent& e)
141
    {
142
        TreeViewItem::itemDoubleClicked(e);
1555 tk 143
        if( getOwnerView()->isEnabled() )
144
            browser->treeItemDoubleClicked(this);
1542 tk 145
    }
146
 
1724 tk 147
    var getDragSourceDescription()
1542 tk 148
    {
149
        return "MIOS Filebrowser Items";
150
    }
151
 
1763 tk 152
 
1542 tk 153
private:
154
};
155
 
156
//==============================================================================
157
//==============================================================================
158
//==============================================================================
159
MiosFileBrowser::MiosFileBrowser(MiosStudio *_miosStudio)
160
    : miosStudio(_miosStudio)
161
    , rootItem(NULL)
162
    , rootFileItem(NULL)
1546 tk 163
    , currentDirOpenStates(NULL)
1554 tk 164
    , transferSelectionCtr(0)
165
    , openTextEditorAfterRead(false)
166
    , openHexEditorAfterRead(false)
1542 tk 167
    , currentReadInProgress(false)
1555 tk 168
    , currentReadFileBrowserItem(NULL)
1554 tk 169
    , currentReadFileStream(NULL)
1542 tk 170
    , currentReadError(false)
171
    , currentWriteInProgress(false)
172
    , currentWriteError(false)
1548 tk 173
    , writeBlockCtrDefault(32) // send 32 blocks (=two 512 byte SD Card Sectors) at once to speed-up write operations
174
    , writeBlockSizeDefault(32) // send 32 bytes per block
1542 tk 175
{
1554 tk 176
    addAndMakeVisible(editLabel = new Label(T("Edit"), String::empty));
177
    editLabel->setJustificationType(Justification::left);
2180 tk 178
    editLabel->setText(String::empty, sendNotification);
1554 tk 179
 
1542 tk 180
    addAndMakeVisible(statusLabel = new Label(T("Status"), String::empty));
181
    statusLabel->setJustificationType(Justification::left);
2180 tk 182
    statusLabel->setText(T("Please connect to MIOS32 core by pressing the Update button!"), sendNotification);
1542 tk 183
 
1554 tk 184
    addAndMakeVisible(updateButton = new TextButton(T("Update")));
1542 tk 185
    updateButton->addListener(this);
186
 
1554 tk 187
    addAndMakeVisible(uploadButton = new TextButton(T("Upload")));
1542 tk 188
    uploadButton->addListener(this);
189
 
1554 tk 190
    addAndMakeVisible(downloadButton = new TextButton(T("Download")));
1542 tk 191
    downloadButton->addListener(this);
192
 
1554 tk 193
    addAndMakeVisible(editTextButton = new TextButton(T("Edit Text")));
1542 tk 194
    editTextButton->addListener(this);
195
 
1554 tk 196
    addAndMakeVisible(editHexButton = new TextButton(T("Edit Hex")));
1542 tk 197
    editHexButton->addListener(this);
198
 
1554 tk 199
    addAndMakeVisible(createDirButton = new TextButton(T("Create Dir")));
1542 tk 200
    createDirButton->addListener(this);
201
 
1555 tk 202
    addAndMakeVisible(createFileButton = new TextButton(T("Create File")));
203
    createFileButton->addListener(this);
204
 
1542 tk 205
    addAndMakeVisible(removeButton = new TextButton(T("Remove Button")));
206
    removeButton->setButtonText(T("Remove"));
207
    removeButton->addListener(this);
208
 
1554 tk 209
    addAndMakeVisible(cancelButton = new TextButton(T("Cancel")));
210
    cancelButton->addListener(this);
211
    cancelButton->setEnabled(false);
212
 
213
    addAndMakeVisible(saveButton = new TextButton(T("Save")));
214
    saveButton->addListener(this);
215
    saveButton->setEnabled(false);
216
 
1545 tk 217
    addAndMakeVisible(treeView = new TreeView(T("SD Card")));
1554 tk 218
    treeView->setMultiSelectEnabled(true);
1542 tk 219
 
1554 tk 220
    addAndMakeVisible(hexEditor = new HexTextEditor(statusLabel));
221
    hexEditor->setReadOnly(true);
222
 
223
    addAndMakeVisible(textEditor = new TextEditor(String::empty));
224
    textEditor->setMultiLine(true);
225
    textEditor->setReturnKeyStartsNewLine(true);
226
    textEditor->setReadOnly(false);
227
    textEditor->setScrollbarsShown(true);
228
    textEditor->setCaretVisible(true);
229
    textEditor->setPopupMenuEnabled(true);
230
    textEditor->setReadOnly(true);
231
    textEditor->setVisible(false); // either hex or text editor visible
232
#if JUCE_MAJOR_VERSION==1 && JUCE_MINOR_VERSION<51
233
#if defined(JUCE_WIN32)
234
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 10.0, 0));
235
#else
236
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 13.0, 0));
237
#endif
238
#else
239
#if defined(JUCE_WIN32)
240
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 10.0, 0));
241
#else
242
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 13.0, 0));
243
#endif
244
#endif
245
    textEditor->addListener(this);
246
 
1545 tk 247
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
248
    currentDirItem = rootFileItem;
1542 tk 249
    updateTreeView(false);
250
 
1554 tk 251
    resizeLimits.setSizeLimits(500, 320, 2048, 2048);
1542 tk 252
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
253
 
1554 tk 254
    setSize(950, 500);
1542 tk 255
}
256
 
257
MiosFileBrowser::~MiosFileBrowser()
258
{
259
}
260
 
261
//==============================================================================
262
void MiosFileBrowser::paint (Graphics& g)
263
{
264
    //g.fillAll(Colour(0xffc1d0ff));
265
    g.fillAll(Colour(0xffffffff));
266
}
267
 
268
void MiosFileBrowser::resized()
269
{
270
    int sendButtonY = 16;
271
    int sendButtonWidth = 72;
1555 tk 272
 
273
    updateButton->setBounds    (10 , sendButtonY + 0*32 + 0*16, sendButtonWidth, 24);
274
    downloadButton->setBounds  (10 , sendButtonY + 1*32 + 1*16, sendButtonWidth, 24);
275
    uploadButton->setBounds    (10 , sendButtonY + 2*32 + 1*16, sendButtonWidth, 24);
276
    createDirButton->setBounds (10 , sendButtonY + 3*32 + 3*16, sendButtonWidth, 24);
277
    createFileButton->setBounds(10 , sendButtonY + 4*32 + 3*16, sendButtonWidth, 24);
278
    removeButton->setBounds    (10 , sendButtonY + 5*32 + 4*16, sendButtonWidth, 24);
1542 tk 279
 
1555 tk 280
    treeView->setBounds        (10 + 80, 16, 210, getHeight()-32-24);
1542 tk 281
 
1555 tk 282
    hexEditor->setBounds       (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
283
    textEditor->setBounds      (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
1542 tk 284
 
1555 tk 285
    editTextButton->setBounds  (10+80+220 + 0*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
286
    editHexButton->setBounds   (10+80+220 + 1*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
287
    cancelButton->setBounds    (getWidth()-10-sendButtonWidth, sendButtonY, sendButtonWidth, 24);
288
    saveButton->setBounds      (getWidth()-10-2*sendButtonWidth-10, sendButtonY, sendButtonWidth, 24);
1554 tk 289
 
290
    unsigned editLabelLeft  = editHexButton->getX()+editHexButton->getWidth() + 10;
291
    unsigned editLabelRight = saveButton->getX() - 10;
1555 tk 292
    editLabel->setBounds       (editLabelLeft, sendButtonY, editLabelRight-editLabelLeft, 24);
1554 tk 293
 
1542 tk 294
    statusLabel->setBounds(10, getHeight()-24, getWidth()-20, 24);
295
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
296
}
297
 
298
//==============================================================================
1759 tk 299
void MiosFileBrowser::setStatus(const String& str)
300
{
301
    if( miosStudio->runningInBatchMode() ) {
302
        std::cout << str << std::endl;
303
    } else {
2180 tk 304
        statusLabel->setText(str, sendNotification);
1759 tk 305
    }
306
}
307
 
308
//==============================================================================
1542 tk 309
void MiosFileBrowser::buttonClicked(Button* buttonThatWasClicked)
310
{
311
    if( buttonThatWasClicked == updateButton ) {
1546 tk 312
        // ensure that we see the first position of the treeview
313
        treeView->clearSelectedItems();
314
        treeView->scrollToKeepItemVisible(rootItem);
1548 tk 315
        // change label
1759 tk 316
        setStatus(T(""));
1546 tk 317
        // request update
318
        requestUpdateTreeView();
1542 tk 319
    } else if( buttonThatWasClicked == downloadButton ||
320
               buttonThatWasClicked == editTextButton ||
321
               buttonThatWasClicked == editHexButton ) {
322
 
1554 tk 323
        // extra: if data is edited, switch between hex/text view
324
        if( saveButton->isEnabled() ) {
1555 tk 325
            // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
326
            if( currentReadFileBrowserItem ) {
327
                currentReadFileBrowserItem->setSelected(true, true);
328
                treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
329
            }
330
 
1554 tk 331
            if( buttonThatWasClicked == editTextButton && hexEditor->isVisible() ) {
1555 tk 332
                openTextEditor(hexEditor->getBinary());
1759 tk 333
                setStatus(T("Editing ") + currentReadFileName + T(" in text mode."));
1554 tk 334
            } else if( buttonThatWasClicked == editHexButton && textEditor->isVisible() ) {
1555 tk 335
                if( textEditor->isVisible() && !textEditor->isReadOnly() ) {
336
                    // visible & read only mode means, that binary data is edited -> transfer to Hex Editor only in this case!
337
                    String tmpStr(textEditor->getText());
1724 tk 338
                    Array<uint8> data((uint8 *)tmpStr.toUTF8().getAddress(), tmpStr.length());
1555 tk 339
                    openHexEditor(data);
340
                } else {
341
                    // otherwise re-use data in hex editor
342
                    openHexEditor(hexEditor->getBinary());
343
                }
1759 tk 344
                setStatus(T("Editing ") + currentReadFileName + T(" in hex mode."));
1554 tk 345
            }
346
        } else {
347
            if( treeView->getNumSelectedItems() ) {
348
                openTextEditorAfterRead = buttonThatWasClicked == editTextButton;
349
                openHexEditorAfterRead = buttonThatWasClicked == editHexButton;
350
                transferSelectionCtr = 0;
351
                downloadFileSelection(transferSelectionCtr);
352
            }
1542 tk 353
        }
354
    } else if( buttonThatWasClicked == uploadButton ) {
1554 tk 355
        uploadFile();
1542 tk 356
    } else if( buttonThatWasClicked == createDirButton ) {
1554 tk 357
        createDir();
1555 tk 358
    } else if( buttonThatWasClicked == createFileButton ) {
359
        createFile();
1542 tk 360
    } else if( buttonThatWasClicked == removeButton ) {
361
        if( treeView->getNumSelectedItems() ) {
1554 tk 362
            transferSelectionCtr = 0;
363
            deleteFileSelection(transferSelectionCtr);
364
        }
365
    } else if( buttonThatWasClicked == cancelButton ||
366
               buttonThatWasClicked == saveButton ) {
367
 
368
        if( buttonThatWasClicked == cancelButton ) {
1594 tk 369
            openHexEditorAfterRead = false;
370
            openTextEditorAfterRead = false;
1554 tk 371
            enableFileButtons();
372
            hexEditor->clear();
373
            hexEditor->setReadOnly(true);
374
            textEditor->clear();
375
            textEditor->setReadOnly(true);
2180 tk 376
            editLabel->setText(String::empty, sendNotification);
1554 tk 377
 
378
            disableFileButtons(); // to disable also editor buttons
379
            enableFileButtons();
380
        } else if( buttonThatWasClicked == saveButton ) {
381
            if( hexEditor->isVisible() ) {
382
                // write back the read file
383
                uploadBuffer(currentReadFileName, hexEditor->getBinary());
384
            } else if( textEditor->isVisible() ) {
385
                // write back the read file
386
                String txt(textEditor->getText());
1724 tk 387
                Array<uint8> tmp((uint8 *)txt.toUTF8().getAddress(), txt.length());
1554 tk 388
                uploadBuffer(currentReadFileName, tmp);
1542 tk 389
            }
390
        }
391
    }
392
}
393
 
394
 
395
//==============================================================================
1554 tk 396
void MiosFileBrowser::textEditorTextChanged(TextEditor &editor)
1542 tk 397
{
1554 tk 398
    // unfortunately not updated on any cursor move...
399
#if 0
400
    int pos = editor.getCaretPosition();
401
    String txt(editor.getText());
1759 tk 402
    setStatus(String::formatted(T("(%d/%d)"), pos, txt.length()));
1554 tk 403
#endif
1542 tk 404
}
405
 
1554 tk 406
void MiosFileBrowser::textEditorReturnKeyPressed(TextEditor &editor)
407
{
408
}
409
 
410
void MiosFileBrowser::textEditorEscapeKeyPressed(TextEditor &editor)
411
{
412
}
413
 
414
void MiosFileBrowser::textEditorFocusLost(TextEditor &editor)
415
{
416
}
417
 
418
 
1542 tk 419
//==============================================================================
1545 tk 420
String MiosFileBrowser::getSelectedPath(void)
421
{
422
    String selectedPath(T("/"));
423
 
424
    TreeViewItem* selectedItem = treeView->getSelectedItem(0);
425
    if( selectedItem ) {
426
        selectedPath = selectedItem->getUniqueName();
427
        if( selectedPath.compare(T("/")) != 0 ) {
428
            if( !selectedItem->mightContainSubItems() ) {
429
                selectedPath = selectedPath.substring(0, selectedPath.lastIndexOfChar('/')) + T("/");
430
            } else {
431
                selectedPath += T("/");
432
            }
433
        }
434
    }
435
 
436
    //std::cout << "Selected Path: " << selectedPath << std::endl;
437
 
438
    return selectedPath;
439
}
440
 
441
//==============================================================================
1542 tk 442
void MiosFileBrowser::disableFileButtons(void)
443
{
1554 tk 444
    updateButton->setEnabled(true);
1542 tk 445
    uploadButton->setEnabled(false);
446
    downloadButton->setEnabled(false);
447
    createDirButton->setEnabled(false);
1555 tk 448
    createFileButton->setEnabled(false);
1542 tk 449
    removeButton->setEnabled(false);
1554 tk 450
 
451
    // important: don't disable save/cancel button as long as an open editor has content
452
    // (in case of write error)
453
    if( !(textEditor->isVisible() && textEditor->getText().length()) &&
454
        !(hexEditor->isVisible() && hexEditor->getBinary().size()) ) {
455
        editTextButton->setEnabled(false);
456
        editHexButton->setEnabled(false);
457
        hexEditor->setReadOnly(true);
458
        textEditor->setReadOnly(true);
459
        saveButton->setEnabled(false);
460
        cancelButton->setEnabled(false);
461
    }
1542 tk 462
}
463
 
464
void MiosFileBrowser::enableFileButtons(void)
465
{
1724 tk 466
    treeView->setEnabled(true);
467
 
1554 tk 468
    updateButton->setEnabled(true);
1542 tk 469
    uploadButton->setEnabled(true);
470
    downloadButton->setEnabled(true);
471
    editTextButton->setEnabled(true);
472
    editHexButton->setEnabled(true);
473
    createDirButton->setEnabled(true);
1555 tk 474
    createFileButton->setEnabled(true);
1542 tk 475
    removeButton->setEnabled(true);
476
}
477
 
478
void MiosFileBrowser::enableDirButtons(void)
479
{
1554 tk 480
    updateButton->setEnabled(true);
1545 tk 481
    uploadButton->setEnabled(true);
1542 tk 482
    createDirButton->setEnabled(true);
1555 tk 483
    createFileButton->setEnabled(true); // no error: we want to create a file in the selected directory
1542 tk 484
    removeButton->setEnabled(true);
485
}
486
 
1554 tk 487
void MiosFileBrowser::enableEditorButtons(void)
488
{
489
    treeView->setEnabled(false);
1555 tk 490
 
1554 tk 491
    updateButton->setEnabled(false);
492
    editTextButton->setEnabled(true);
493
    editHexButton->setEnabled(true);
494
    cancelButton->setEnabled(true);
495
    saveButton->setEnabled(true);
496
}
497
 
1555 tk 498
//==============================================================================
499
String MiosFileBrowser::convertToString(const Array<uint8>& data, bool& hasBinaryData)
500
{
501
    String str;
502
    hasBinaryData = false;
503
 
504
    uint8 *ptr = (uint8 *)&data.getReference(0);
505
    for(int i=0; i<data.size(); ++i, ++ptr) {
506
        if( *ptr == 0 ) {
507
            hasBinaryData = true; // full conversion to string not possible
1724 tk 508
            str += "\\0"; // show \0 instead
1555 tk 509
        } else {
1724 tk 510
            str += (const wchar_t)*ptr;
1555 tk 511
        }
512
    }
1554 tk 513
 
1555 tk 514
    return str;
515
}
516
 
517
bool MiosFileBrowser::updateEditors(const Array<uint8>& data)
518
{
519
    // transfer data into both editors, make them read-only and invisible
520
    hexEditor->setReadOnly(false);
521
    hexEditor->clear();
522
    hexEditor->addBinary((uint8 *)&data.getReference(0), data.size());
523
    hexEditor->setReadOnly(true);
524
    hexEditor->setVisible(false);
525
 
526
    bool hasBinaryData = false;
527
    String tmpStr(convertToString(data, hasBinaryData));
528
    textEditor->setReadOnly(false);
529
    textEditor->clear();
530
    textEditor->setText(tmpStr, true);
531
    textEditor->setReadOnly(true);
532
    textEditor->setVisible(false);
533
 
534
    // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
535
    if( currentReadFileBrowserItem ) {
536
        currentReadFileBrowserItem->setSelected(true, true);
537
        treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
538
    }
539
 
540
    return hasBinaryData;
541
}
542
 
543
void MiosFileBrowser::openTextEditor(const Array<uint8>& data)
544
{
545
    // transfer data to both editors
546
    bool hasBinaryData = updateEditors(data);
547
 
548
    disableFileButtons();
549
    enableEditorButtons();
550
 
551
    // make text editor visible and enable read access if no binary data
552
    textEditor->setVisible(true);
553
    if( !hasBinaryData ) {
554
        textEditor->setReadOnly(false);
555
    } else {
1726 tk 556
        // TK: crashes Juce2 - it seems that we are not allowed to use an AlertWindow from the MiosStudio::timerCallback() thread
557
#if 0
1555 tk 558
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
559
                                    T("Found binary data!"),
560
                                    T("This file contains binary data, therefore it\nisn't possible modify it with the text editor!\nPlease use the hex editor instead!"),
561
                                    T("Ok"));
1726 tk 562
#endif
1555 tk 563
    }
1734 tk 564
    textEditor->setCaretVisible(true); // TK: required since Juce2 - I don't know why...
1555 tk 565
}
566
 
567
void MiosFileBrowser::openHexEditor(const Array<uint8>& data)
568
{
569
    // transfer data to both editors
570
    updateEditors(data);
571
 
572
    disableFileButtons();
573
    enableEditorButtons();
574
 
575
    hexEditor->setVisible(true);
576
    hexEditor->setReadOnly(false);
1734 tk 577
 
578
    hexEditor->setCaretVisible(true); // TK: required since Juce2 - I don't know why...
1555 tk 579
}
580
 
1542 tk 581
//==============================================================================
1546 tk 582
void MiosFileBrowser::requestUpdateTreeView(void)
583
{
1554 tk 584
    treeView->setEnabled(true);
1546 tk 585
    currentDirOpenStates = treeView->getOpennessState(true); // including scroll position
586
 
587
    if( rootFileItem )
588
        delete rootFileItem;
589
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
590
    currentDirItem = rootFileItem;
591
 
592
    updateTreeView(false);
593
 
594
    disableFileButtons();
595
    currentDirFetchItems.clear();
596
    currentDirPath = T("/");
597
    sendCommand(T("dir ") + currentDirPath);
598
}
599
 
1542 tk 600
void MiosFileBrowser::updateTreeView(bool accessPossible)
601
{
602
    disableFileButtons();
603
 
604
    if( rootItem )
605
        treeView->deleteRootItem();
606
 
607
    if( rootFileItem ) {
608
        rootItem = new MiosFileBrowserItem(rootFileItem, this);
609
        rootItem->setOpen(true);
610
        treeView->setRootItem(rootItem);
611
 
1546 tk 612
        if( accessPossible ) {
613
            if( currentDirOpenStates ) {
1724 tk 614
                treeView->restoreOpennessState(*currentDirOpenStates, true);
1546 tk 615
                deleteAndZero(currentDirOpenStates);
616
            }
1545 tk 617
 
1542 tk 618
            uploadButton->setEnabled(true);
619
            createDirButton->setEnabled(true);
1555 tk 620
            createFileButton->setEnabled(true);
1542 tk 621
        }
622
    }
623
}
624
 
625
void MiosFileBrowser::treeItemClicked(MiosFileBrowserItem* item)
626
{
627
    disableFileButtons();
628
 
629
    if( item->fileItem->isDirectory ) {
630
        enableDirButtons();
631
    } else {
632
        enableFileButtons();
633
    }
634
}
635
 
636
void MiosFileBrowser::treeItemDoubleClicked(MiosFileBrowserItem* item)
637
{
638
}
639
 
640
//==============================================================================
1554 tk 641
bool MiosFileBrowser::downloadFileSelection(unsigned selection)
1542 tk 642
{
1554 tk 643
    treeView->setEnabled(false);
644
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
1555 tk 645
    currentReadFileBrowserItem = selectedItem;
1542 tk 646
 
1554 tk 647
    if( selectedItem ) {
648
        currentReadFileName = selectedItem->getUniqueName();
1542 tk 649
 
1554 tk 650
        if( openHexEditorAfterRead || openTextEditorAfterRead ) {
651
            disableFileButtons();
652
            sendCommand(T("read ") + currentReadFileName);
653
            return true;
654
        } else {
655
            // restore default path
656
            String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
1724 tk 657
            PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1554 tk 658
            if( propertiesFile ) {
659
                defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
660
            }
661
 
662
            String readFileName(currentReadFileName.substring(currentReadFileName.lastIndexOfChar('/')+1));
663
            File defaultPathFile(defaultPath + "/" + readFileName);
664
            FileChooser myChooser(T("Store ") + currentReadFileName, defaultPathFile);
665
            if( !myChooser.browseForFileToSave(true) ) {
1759 tk 666
                setStatus(T("Cancled save operation for ") + currentReadFileName);
1554 tk 667
            } else {
668
                currentReadFile = myChooser.getResult();
669
 
670
                // store default path
671
                if( propertiesFile ) {
672
                    propertiesFile->setValue(T("defaultFilebrowserPath"), currentReadFile.getParentDirectory().getFullPathName());
673
                }
674
 
675
                currentReadFileStream = NULL;
676
                currentReadFile.deleteFile();
677
                if( !(currentReadFileStream=currentReadFile.createOutputStream()) ||
678
                    currentReadFileStream->failedToOpen() ) {
679
                    AlertWindow::showMessageBox(AlertWindow::WarningIcon,
680
                                                String::empty,
681
                                                T("File cannot be created!"),
682
                                                String::empty);
1759 tk 683
                    setStatus(T("Failed to open ") + currentReadFile.getFullPathName());
1554 tk 684
                } else {
685
                    disableFileButtons();
686
                    sendCommand(T("read ") + currentReadFileName);
687
                    return true;
688
                }
689
            }
1542 tk 690
        }
1554 tk 691
    }
1542 tk 692
 
1554 tk 693
    // operation not successfull (or no more files)
694
    treeView->setEnabled(true);
695
    enableFileButtons();
696
 
697
    return false;
698
}
699
 
700
bool MiosFileBrowser::downloadFinished(void)
701
{
702
    if( openHexEditorAfterRead ) {
1555 tk 703
        openHexEditor(currentReadData);
1759 tk 704
        setStatus(T("Editing ") + currentReadFileName);
2180 tk 705
        editLabel->setText(currentReadFileName, sendNotification);
1554 tk 706
    } else if( openTextEditorAfterRead ) {
1555 tk 707
        openTextEditor(currentReadData);
1759 tk 708
        setStatus(T("Editing ") + currentReadFileName);
2180 tk 709
        editLabel->setText(currentReadFileName, sendNotification);
1554 tk 710
    } else if( currentReadFileStream ) {
711
        currentReadFileStream->write((uint8 *)&currentReadData.getReference(0), currentReadData.size());
712
        delete currentReadFileStream;
1759 tk 713
        setStatus(T("Saved ") + currentReadFile.getFullPathName());
1554 tk 714
 
715
        // try next file (if there is still another selection
716
        downloadFileSelection(++transferSelectionCtr);
717
    }
718
 
719
    return true;
720
}
721
 
722
//==============================================================================
723
bool MiosFileBrowser::deleteFileSelection(unsigned selection)
724
{
725
    treeView->setEnabled(false);
726
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
727
 
728
    if( selectedItem ) {
729
        String fileName(selectedItem->getUniqueName());
730
        if( AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
731
                                         T("Removing ") + fileName,
732
                                         T("Do you really want to remove\n") + fileName + T("?"),
733
                                         T("Remove"),
734
                                         T("Cancel")) ) {
735
            disableFileButtons();
736
            sendCommand(T("del ") + fileName);
737
            return true;
1542 tk 738
        }
739
    }
740
 
1554 tk 741
    // operation finished
742
    requestUpdateTreeView();
743
 
744
    return false;
745
}
746
 
747
bool MiosFileBrowser::deleteFinished(void)
748
{
1759 tk 749
    setStatus(T("File has been removed!"));
1554 tk 750
 
751
    // try next file (if there is still another selection
752
    deleteFileSelection(++transferSelectionCtr);
753
 
1542 tk 754
    return true;
755
}
756
 
1554 tk 757
//==============================================================================
758
bool MiosFileBrowser::createDir(void)
759
{
760
    AlertWindow enterName(T("Creating new Directory"),
761
                          T("Please enter directory name:"),
762
                          AlertWindow::QuestionIcon);
763
 
764
    enterName.addButton(T("Create"), 1);
765
    enterName.addButton(T("Cancel"), 0);
766
    enterName.addTextEditor(T("Name"), String::empty);
767
 
768
    if( enterName.runModalLoop() ) {
769
        String name(enterName.getTextEditorContents(T("Name")));
770
        if( name.length() ) {
1555 tk 771
            if( name[0] == '/' )
772
                sendCommand(T("mkdir ") + name);
773
            else
774
                sendCommand(T("mkdir ") + getSelectedPath() + name);
1554 tk 775
        }        
776
    }
777
 
778
    return false;
779
}
780
 
781
bool MiosFileBrowser::createDirFinished(void)
782
{
1759 tk 783
    setStatus(T("Directory has been created!"));
1554 tk 784
 
785
    requestUpdateTreeView();
786
 
787
    return true;
788
}
789
 
790
//==============================================================================
1555 tk 791
bool MiosFileBrowser::createFile(void)
792
{
793
    AlertWindow enterName(T("Creating new File"),
794
                          T("Please enter filename:"),
795
                          AlertWindow::QuestionIcon);
796
 
797
    enterName.addButton(T("Create"), 1);
798
    enterName.addButton(T("Cancel"), 0);
799
    enterName.addTextEditor(T("Name"), String::empty);
800
 
801
    if( enterName.runModalLoop() ) {
802
        String name(enterName.getTextEditorContents(T("Name")));
803
        if( name.length() ) {
804
            Array<uint8> emptyBuffer;
805
            if( name[0] == '/' )
806
                return uploadBuffer(name, emptyBuffer);
807
            else
808
                return uploadBuffer(getSelectedPath() + name, emptyBuffer);
809
        }        
810
    }
811
 
812
    return false;
813
}
814
 
815
//==============================================================================
1759 tk 816
bool MiosFileBrowser::uploadFile(String filename)
1542 tk 817
{
818
    // restore default path
819
    String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
1724 tk 820
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1542 tk 821
    if( propertiesFile ) {
822
        defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
823
    }
824
    File defaultPathFile(defaultPath);
825
    FileChooser myChooser(T("Upload File to Core"), defaultPathFile);
1759 tk 826
    if( !filename.length() && !myChooser.browseForFileToOpen() ) {
1542 tk 827
        return false;
1759 tk 828
    }
1542 tk 829
 
1759 tk 830
    File inFile(filename.length() ? filename : myChooser.getResult());
1542 tk 831
 
1759 tk 832
    // store default path
833
    if( propertiesFile ) {
834
        propertiesFile->setValue(T("defaultFilebrowserPath"), inFile.getParentDirectory().getFullPathName());
835
    }
836
 
837
    FileInputStream *inFileStream = inFile.createInputStream();
838
    if( !inFileStream || inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
839
        if( miosStudio->runningInBatchMode() ) {
840
            std::cerr << "The file " << inFile.getFileName() << " doesn't exist!" << std::endl;
841
        } else {
1542 tk 842
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
843
                                        T("The file ") + inFile.getFileName(),
844
                                        T("doesn't exist!"),
845
                                        String::empty);
1759 tk 846
        }
847
    } else if( inFileStream->isExhausted() ) { // || !inFileStream->getTotalLength() -> disabled, we also want to handle zero-length files
848
        if( miosStudio->runningInBatchMode() ) {
849
            std::cerr << "The file " << inFile.getFileName() << " can't be read!" << std::endl;
850
        } else {
1542 tk 851
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
852
                                        T("The file ") + inFile.getFileName(),
1555 tk 853
                                        T("can't be read!"),
1542 tk 854
                                        String::empty);
855
        }
1759 tk 856
    } else {
857
        disableFileButtons();
858
 
859
        uint64 size = inFileStream->getTotalLength();
860
        uint8 *buffer = (uint8 *)juce_malloc(size);
861
        size = inFileStream->read(buffer, size);
862
        //currentWriteData.resize(currentWriteSize); // doesn't exist in Juce 1.53
863
        Array<uint8> tmp(buffer, size);
864
        juce_free(buffer);
865
        uploadBuffer(getSelectedPath() + inFile.getFileName(), tmp);
1542 tk 866
    }
867
 
1759 tk 868
    if( inFileStream )
869
        delete inFileStream;
870
 
1542 tk 871
    return true;
872
}
873
 
1554 tk 874
bool MiosFileBrowser::uploadBuffer(String filename, const Array<uint8>& buffer)
875
{
876
    currentWriteFileName = filename;
877
    currentWriteData = buffer;
878
    currentWriteSize = buffer.size();
879
 
1759 tk 880
    setStatus(T("Uploading ") + currentWriteFileName + T(" (") + String(currentWriteSize) + T(" bytes)"));
1554 tk 881
 
882
    currentWriteInProgress = true;
883
    currentWriteError = false;
884
    currentWriteFirstBlockOffset = 0;
885
    currentWriteBlockCtr = writeBlockCtrDefault;
886
    currentWriteStartTime = Time::currentTimeMillis();
887
    sendCommand(T("write ") + currentWriteFileName + T(" ") + String(currentWriteSize));
1564 tk 888
    startTimer(5000);
1554 tk 889
 
890
    return true;
891
}
892
 
893
bool MiosFileBrowser::uploadFinished(void)
894
{
895
    currentWriteInProgress = false;
1594 tk 896
    String extraText;
1554 tk 897
 
898
    // finished edit operation?
899
    if( openHexEditorAfterRead || openTextEditorAfterRead ) {
1594 tk 900
#if 0
1554 tk 901
        openHexEditorAfterRead = false;
902
        openTextEditorAfterRead = false;
903
        hexEditor->clear();
904
        hexEditor->setReadOnly(true);
905
        textEditor->clear();
906
        textEditor->setReadOnly(true);
907
        editLabel->setText(String::empty, true);
1594 tk 908
#else
909
        extraText = T(" - you can continue editing; click CANCEL to close editor!");
910
        // don't close editor
911
#endif
1554 tk 912
    }
913
 
914
    uint32 currentWriteFinished = Time::currentTimeMillis();
915
    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
916
    float dataRate = ((float)currentWriteSize/1000.0) / downloadTime;
917
 
1594 tk 918
 
1759 tk 919
    setStatus(T("Upload of ") + currentWriteFileName +
1554 tk 920
                         T(" (") + String(currentWriteSize) + T(" bytes) completed in ") +
1594 tk 921
                         String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate) +
1759 tk 922
                         extraText);
1554 tk 923
 
1594 tk 924
#if 0 // not required
1554 tk 925
    requestUpdateTreeView();
1594 tk 926
#else
927
    if( !openHexEditorAfterRead && !openTextEditorAfterRead ) {
928
        enableFileButtons();
929
    }
930
#endif
1554 tk 931
 
1594 tk 932
 
1554 tk 933
    return true;
934
}
935
 
1542 tk 936
//==============================================================================
937
void MiosFileBrowser::timerCallback()
938
{
939
    if( currentReadInProgress ) {
940
        if( currentReadError ) {
1759 tk 941
            setStatus(T("Invalid response from MIOS32 core during read operation!"));
1542 tk 942
        } else {
1759 tk 943
            setStatus(T("No response from MIOS32 core during read operation!"));
1542 tk 944
        }
945
    } else {
1759 tk 946
        setStatus(T("No response from MIOS32 core!"));
1542 tk 947
    }
948
}
949
 
950
//==============================================================================
951
void MiosFileBrowser::sendCommand(const String& command)
952
{
953
    Array<uint8> dataArray = SysexHelper::createMios32DebugMessage(miosStudio->uploadHandler->getDeviceId());
954
    dataArray.add(0x01); // filebrowser string
955
    for(int i=0; i<command.length(); ++i)
956
        dataArray.add(command[i] & 0x7f);
957
    dataArray.add('\n');
958
    dataArray.add(0xf7);
959
    MidiMessage message = SysexHelper::createMidiMessage(dataArray);
960
    miosStudio->sendMidiMessage(message);
1564 tk 961
    startTimer(5000);
1542 tk 962
}
963
 
964
//==============================================================================
965
void MiosFileBrowser::receiveCommand(const String& command)
966
{
967
    String statusMessage;
968
 
969
    stopTimer(); // will be restarted if required
970
 
971
    if( command.length() ) {
972
        switch( command[0] ) {
973
 
974
        ////////////////////////////////////////////////////////////////////
975
        case '?': {
976
            statusMessage = String(T("Command not supported by MIOS32 application - please check if a firmware update is available!"));
977
        } break;
978
 
979
        ////////////////////////////////////////////////////////////////////
980
        case 'D': {
981
            if( command[1] == '!' ) {
982
                statusMessage = String(T("SD Card not mounted!"));
983
            } else if( command[1] == '-' ) {
984
                statusMessage = String(T("Failed to access directory!"));
985
            } else {
1548 tk 986
                //statusMessage = String(T("Received directory structure."));
1542 tk 987
 
988
                int posStartName = 2;
989
                for(int pos=2; pos<command.length(); ++pos) {
990
                    if( command[pos] == 'F' || command[pos] == 'D' ) {
991
                        for(++pos; pos < command.length() && command[pos] != ','; ++pos);
992
                        String fileName(command.substring(posStartName, pos));
993
                        //std::cout << "XXX " << fileName << std::endl;
994
                        if( fileName[0] == 'F' ) {
1545 tk 995
                            currentDirItem->createChild(currentDirPath, fileName.substring(1), false);
1542 tk 996
                        } else if( fileName[0] == 'D' ) {
1545 tk 997
                            currentDirFetchItems.add(currentDirItem->createChild(currentDirPath, fileName.substring(1), true));
1542 tk 998
                        } else {
1545 tk 999
                            std::cout << "INVALID Response: " << currentDirPath << fileName << std::endl;
1542 tk 1000
                            statusMessage = String(T("Invalid Response!"));
1001
                            break;
1002
                        }
1003
                        posStartName = pos+1;
1004
                    } else {
1005
                        statusMessage = String(T("Invalid Response!"));
1006
                        break;
1007
                    }
1008
                }
1009
            }
1545 tk 1010
 
1011
            // do we have to fetch some additional subdirectories?
1012
            if( currentDirFetchItems.size() ) {
1013
                currentDirItem = currentDirFetchItems.remove(0);
1014
                if( currentDirItem->parentPath.compare(T("/")) == 0 )
1015
                    currentDirPath = currentDirItem->parentPath + currentDirItem->name;
1016
                else
1017
                    currentDirPath = currentDirItem->parentPath + T("/") + currentDirItem->name;
1018
                //std::cout << "Fetch " << currentDirPath << std::endl;
1019
                sendCommand(T("dir ") + currentDirPath);
1020
            } else {
1021
                updateTreeView(true);
1022
            }
1542 tk 1023
        } break;
1024
 
1025
        ////////////////////////////////////////////////////////////////////
1026
        case 'R': {
1027
            if( command[1] == '!' ) {
1028
                statusMessage = String(T("SD Card not mounted!"));
1029
            } else if( command[1] == '-' ) {
1554 tk 1030
                statusMessage = String(T("Failed to access " + currentReadFileName + "!"));
1542 tk 1031
            } else {
1032
                currentReadSize = (command.substring(1)).getIntValue();
1033
                currentReadData.clear();
1034
                if( currentReadSize ) {
1554 tk 1035
                    statusMessage = String(T("Receiving ") + currentReadFileName + T(" with ") + String(currentReadSize) + T(" bytes."));
1542 tk 1036
                    currentReadInProgress = true;
1037
                    currentReadError = false;
1038
                    currentReadStartTime = Time::currentTimeMillis();
1564 tk 1039
                    startTimer(5000);
1542 tk 1040
                } else {
1554 tk 1041
                    statusMessage = String(currentReadFileName + T(" is empty!"));
1555 tk 1042
                    // ok, we accept this to edit zero-length files
1043
                    // fake transfer:
1044
                    currentReadInProgress = false;
1045
                    currentReadData.clear();
1759 tk 1046
                    setStatus(statusMessage);
1555 tk 1047
                    downloadFinished();
1048
                    statusMessage = String::empty; // status has been updated by downloadFinished()
1542 tk 1049
                }
1050
            }
1051
        } break;
1052
 
1053
        ////////////////////////////////////////////////////////////////////
1054
        case 'r': {
1055
            if( !currentReadInProgress ) {
1056
                statusMessage = String(T("There is a read operation in progress - please wait!"));
1057
            } else {
1058
                String strAddress = command.substring(1, 9);
1059
                String strPayload = command.substring(10);
1060
 
1061
                unsigned address = strAddress.getHexValue32();
1062
 
1063
                if( address >= currentReadSize ) {
1554 tk 1064
                    statusMessage = String(currentReadFileName + T(" received invalid payload!"));
1542 tk 1065
                    currentReadError = true;
1066
                } else {
1067
                    for(int pos=0; pos<strPayload.length(); pos+=2) {
1068
                        uint8 b = (strPayload.substring(pos, pos+2)).getHexValue32();
1069
                        currentReadData.set(address + (pos/2), b);
1070
                    }
1071
 
1072
                    unsigned receivedSize = currentReadData.size();
1073
                    uint32 currentReadFinished = Time::currentTimeMillis();
1074
                    float downloadTime = (float)(currentReadFinished-currentReadStartTime) / 1000.0;
1075
                    float dataRate = ((float)receivedSize/1000.0) / downloadTime;
1076
                    if( receivedSize >= currentReadSize ) {
1554 tk 1077
                        statusMessage = String(T("Download of ") + currentReadFileName +
1542 tk 1078
                                               T(" (") + String(receivedSize) + T(" bytes) completed in ") +
1079
                                               String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate));
1080
                        currentReadInProgress = false;
1081
 
1759 tk 1082
                        setStatus(statusMessage);
1554 tk 1083
                        downloadFinished();
1084
                        statusMessage = String::empty; // status has been updated by downloadFinished()
1542 tk 1085
                    } else {
1554 tk 1086
                        statusMessage = String(T("Downloading ") + currentReadFileName + T(": ") +
1542 tk 1087
                                               String(receivedSize) + T(" bytes received") +
1088
                                               String::formatted(T(" (%d%%, %2.1f kb/s)"),
1089
                                                                 (int)(100.0*(float)receivedSize/(float)currentReadSize),
1090
                                                                 dataRate));
1564 tk 1091
                        startTimer(5000);
1542 tk 1092
                    }
1093
                }
1094
            }
1095
        } break;
1096
 
1097
        ////////////////////////////////////////////////////////////////////
1098
        case 'W': {
1548 tk 1099
            if( currentWriteError ) {
1100
                // ignore
1101
            } else if( !currentWriteInProgress ) {
1542 tk 1102
                statusMessage = String(T("There is a write operation in progress - please wait!"));
1103
            } else if( command[1] == '!' ) {
1104
                statusMessage = String(T("SD Card not mounted!"));
1105
            } else if( command[1] == '-' ) {
1554 tk 1106
                statusMessage = String(T("Failed to access " + currentWriteFileName + "!"));
1542 tk 1107
            } else if( command[1] == '~' ) {
1108
                statusMessage = String(T("FATAL: invalid parameters for write operation!"));
1109
            } else if( command[1] == '#' ) {
1554 tk 1110
                uploadFinished();
1111
                statusMessage = String::empty; // status has been updated by uploadFinished()
1542 tk 1112
            } else {
1113
                unsigned addressOffset = command.substring(1).getHexValue32();
1114
 
1548 tk 1115
                if( currentWriteBlockCtr < writeBlockCtrDefault ) {
1116
                    // check for valid response
1117
                    unsigned expectedOffset = currentWriteFirstBlockOffset + (writeBlockSizeDefault*(currentWriteBlockCtr+1));
1118
                    if( addressOffset != expectedOffset ) {
1119
                        currentWriteError = true;
1759 tk 1120
                        setStatus(String::formatted(T("ERROR: the application has requested file position 0x%08X, but filebrowser expected 0x%08X! Please check with TK!"), addressOffset, expectedOffset));
1548 tk 1121
                    } else {
1122
                        ++currentWriteBlockCtr; // block received
1123
                    }                    
1542 tk 1124
                }
1125
 
1548 tk 1126
                // new burst?
1127
                if( currentWriteBlockCtr >= writeBlockCtrDefault ) {
1128
                    currentWriteFirstBlockOffset = addressOffset;
1129
                    currentWriteBlockCtr = 0;
1542 tk 1130
 
1548 tk 1131
                    for(unsigned block=0; block<writeBlockCtrDefault; ++block, addressOffset += writeBlockSizeDefault) {
1132
                        String writeCommand(String::formatted(T("writedata %08X "), addressOffset));
1133
                        for(int i=0; i<writeBlockSizeDefault && (i+addressOffset)<currentWriteSize; ++i) {
1134
                            writeCommand += String::formatted(T("%02X"), currentWriteData[addressOffset + i]);
1135
                        }
1136
                        sendCommand(writeCommand);
1137
 
1138
                        if( (writeBlockSizeDefault+addressOffset) >= currentWriteSize )
1139
                            break;
1140
                    }
1141
 
1142
                    uint32 currentWriteFinished = Time::currentTimeMillis();
1143
                    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
1144
                    float dataRate = ((float)addressOffset/1000.0) / downloadTime;
1145
 
1554 tk 1146
                    statusMessage = String(T("Uploading ") + currentWriteFileName + T(": ") +
1548 tk 1147
                                           String(addressOffset) + T(" bytes transmitted") +
1148
                                           String::formatted(T(" (%d%%, %2.1f kb/s)"),
1149
                                                             (int)(100.0*(float)addressOffset/(float)currentWriteSize),
1150
                                                             dataRate));
1564 tk 1151
                    startTimer(5000);
1548 tk 1152
                }
1542 tk 1153
            }
1154
        } break;
1155
 
1156
 
1157
        ////////////////////////////////////////////////////////////////////
1158
        case 'M': {
1159
            if( command[1] == '!' ) {
1160
                statusMessage = String(T("SD Card not mounted!"));
1161
            } else if( command[1] == '-' ) {
1162
                statusMessage = String(T("Failed to create directory!"));
1163
            } else if( command[1] == '#' ) {
1554 tk 1164
                createDirFinished();
1165
                statusMessage = String::empty; // status has been updated by createDirFinished()
1542 tk 1166
            } else {
1167
                statusMessage = String(T("Unsupported response from mkdir command!"));
1168
            }
1169
        } break;
1170
 
1171
 
1172
        ////////////////////////////////////////////////////////////////////
1173
        case 'X': {
1174
            if( command[1] == '!' ) {
1175
                statusMessage = String(T("SD Card not mounted!"));
1176
            } else if( command[1] == '-' ) {
1177
                statusMessage = String(T("Failed to delete file!"));
1178
            } else if( command[1] == '#' ) {
1554 tk 1179
                deleteFinished();
1180
                statusMessage = String::empty; // status has been updated by deleteFinished()
1542 tk 1181
            } else {
1182
                statusMessage = String(T("Unsupported response from del command!"));
1183
            }
1184
        } break;
1185
 
1186
 
1187
        ////////////////////////////////////////////////////////////////////
1188
        default:
1189
            statusMessage = String(T("Received unsupported Filebrowser Command! Please update your MIOS Studio installation!"));
1190
        }
1191
    }
1192
 
1193
    if( statusMessage.length() ) {
1759 tk 1194
        setStatus(statusMessage);
1542 tk 1195
    }
1196
}
1197
 
1198
//==============================================================================
1759 tk 1199
bool MiosFileBrowser::uploadFileInProgress(void)
1200
{
1201
    return currentWriteInProgress || currentReadInProgress;
1202
}
1203
 
1204
bool MiosFileBrowser::uploadFileFromExternal(const String& filename)
1205
{
1206
    return uploadFile(filename);
1207
}
1208
 
1209
//==============================================================================
1542 tk 1210
void MiosFileBrowser::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
1211
{
1724 tk 1212
    uint8 *data = (uint8 *)message.getRawData();
1542 tk 1213
    uint32 size = message.getRawDataSize();
1214
    int messageOffset = 0;
1215
    bool messageReceived = false;
1216
    if( runningStatus == 0xf0 &&
1217
        SysexHelper::isValidMios32DebugMessage(data, size, -1) &&
1218
        data[7] == 0x41 ) {
1219
            messageOffset = 8;
1220
            messageReceived = true;
1221
    } else if( runningStatus == 0xf0 &&
1222
        SysexHelper::isValidMios32Error(data, size, -1) &&
1223
        data[7] == 0x10 ) {
1224
        stopTimer();
1759 tk 1225
        setStatus(T("Filebrowser access not implemented by this application!"));
1542 tk 1226
    }
1227
 
1228
    if( messageReceived ) {
1229
        String command;
1230
 
1231
        for(int i=messageOffset; i<size; ++i) {
1232
            if( data[i] < 0x80 ) {
1233
                if( data[i] != '\n' || size < (i+1) )
1234
                    command += String::formatted(T("%c"), data[i] & 0x7f);
1235
            }
1236
        }
1237
        receiveCommand(command);
1238
    }
1239
}