| 100 | } |
| 101 | |
| 102 | void MainWindow::tuneToNet(const NetEntry& entry) |
| 103 | { |
| 104 | SliceModel* slice = preferredMemorySlice({}); |
| 105 | if (!slice) { |
| 106 | statusBar()->showMessage(QStringLiteral("Open a slice before tuning to a net."), 3000); |
| 107 | return; |
| 108 | } |
| 109 | if (slice->isLocked()) { |
| 110 | slice->notifyTuneBlockedByLock(); |
| 111 | statusBar()->showMessage(QStringLiteral("Unlock the slice to tune to a net."), 3000); |
| 112 | return; |
| 113 | } |
| 114 | |
| 115 | const int sliceId = slice->sliceId(); |
| 116 | if (!activeSlice() || activeSlice()->sliceId() != sliceId) |
| 117 | setActiveSlice(sliceId); |
| 118 | slice = m_radioModel.slice(sliceId); |
| 119 | if (!slice) |
| 120 | return; |
| 121 | |
| 122 | const double freqMhz = entry.preset.freq; |
| 123 | |
| 124 | // Route the net's frequency change through the canonical tune-and-recenter |
| 125 | // policy — the same AbsoluteJump path a DX-cluster spot uses to jump to an |
| 126 | // arbitrary frequency on any band. applyTuneRequest() moves the slice with |
| 127 | // `slice tune <freq>` (which the radio echoes back as a slice RF_frequency |
| 128 | // status, so the VFO display tracks it) and recenters the panadapter on the |
| 129 | // target, crossing bands as needed. |
| 130 | // |
| 131 | // The previous bespoke path issued `display pan set <pan> band=<key>` first, |
| 132 | // which reloaded the band stack: the radio retuned the slice to that band's |
| 133 | // *last-used* frequency (and echoed it), then emitted no status echo for the |
| 134 | // subsequent net retune — so the VFO display stuck on the band frequency |
| 135 | // while RX/TX ran on the net's (#3918). Reusing applyTuneRequest avoids the |
| 136 | // band-stack reload entirely and keeps the display radio-authoritative. |
| 137 | if (freqMhz > 0.0) |
| 138 | applyTuneRequest(slice, freqMhz, TuneIntent::AbsoluteJump, "net-tune"); |
| 139 | |
| 140 | // Net-specific slice settings the tune policy doesn't cover (a net has no |
| 141 | // radio-side memory slot to "memory apply"). |
| 142 | if (!entry.preset.mode.isEmpty()) |
| 143 | slice->setMode(entry.preset.mode); |
| 144 | if (entry.preset.rxFilterLow != entry.preset.rxFilterHigh) { |
| 145 | m_radioModel.sendCommand(QString("filt %1 %2 %3") |
| 146 | .arg(sliceId) |
| 147 | .arg(entry.preset.rxFilterLow) |
| 148 | .arg(entry.preset.rxFilterHigh)); |
| 149 | } |
| 150 | if (entry.preset.step > 0) |
| 151 | m_radioModel.sendCommand(QString("slice set %1 step=%2").arg(sliceId).arg(entry.preset.step)); |
| 152 | const QString fixup = buildMemoryRecallSliceFixupCommand(sliceId, entry.preset); |
| 153 | if (!fixup.isEmpty()) |
| 154 | m_radioModel.sendCommand(fixup); |
| 155 | |
| 156 | statusBar()->showMessage(QString("Tuned to %1").arg(entry.name), 3000); |
| 157 | } |
| 158 | |
| 159 | void MainWindow::onNetReminderDue(const NetEntry& entry, const QDateTime& occurrenceUtc) |
nothing calls this directly
no test coverage detected