Subversion Repositories svn.mios32

Rev

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